hexapdf 0.46.0 → 1.6.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 (355) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +342 -16
  3. data/LICENSE +1 -1
  4. data/README.md +9 -8
  5. data/examples/009-text_layouter_alignment.rb +4 -0
  6. data/examples/010-text_layouter_inline_boxes.rb +4 -0
  7. data/examples/011-text_layouter_line_wrapping.rb +4 -0
  8. data/examples/012-text_layouter_styling.rb +9 -4
  9. data/examples/013-text_layouter_shapes.rb +5 -0
  10. data/examples/015-boxes.rb +3 -0
  11. data/examples/016-frame_automatic_box_placement.rb +3 -0
  12. data/examples/017-frame_text_flow.rb +3 -0
  13. data/examples/022-outline.rb +5 -1
  14. data/examples/{028-frame_mask_mode.rb → 028-composer_mask_mode.rb} +3 -3
  15. data/lib/hexapdf/cli/batch.rb +1 -1
  16. data/lib/hexapdf/cli/command.rb +65 -65
  17. data/lib/hexapdf/cli/debug_info.rb +98 -0
  18. data/lib/hexapdf/cli/files.rb +1 -1
  19. data/lib/hexapdf/cli/fonts.rb +1 -1
  20. data/lib/hexapdf/cli/form.rb +11 -6
  21. data/lib/hexapdf/cli/image2pdf.rb +1 -1
  22. data/lib/hexapdf/cli/images.rb +19 -4
  23. data/lib/hexapdf/cli/info.rb +1 -1
  24. data/lib/hexapdf/cli/inspect.rb +24 -8
  25. data/lib/hexapdf/cli/merge.rb +1 -1
  26. data/lib/hexapdf/cli/modify.rb +1 -2
  27. data/lib/hexapdf/cli/optimize.rb +6 -6
  28. data/lib/hexapdf/cli/split.rb +1 -1
  29. data/lib/hexapdf/cli/usage.rb +1 -1
  30. data/lib/hexapdf/cli/watermark.rb +1 -1
  31. data/lib/hexapdf/cli.rb +20 -2
  32. data/lib/hexapdf/composer.rb +22 -1
  33. data/lib/hexapdf/configuration.rb +56 -1
  34. data/lib/hexapdf/content/canvas.rb +1 -1
  35. data/lib/hexapdf/content/canvas_composer.rb +1 -1
  36. data/lib/hexapdf/content/color_space.rb +1 -1
  37. data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
  38. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  39. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  40. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  41. data/lib/hexapdf/content/graphic_object.rb +1 -1
  42. data/lib/hexapdf/content/graphics_state.rb +2 -2
  43. data/lib/hexapdf/content/operator.rb +1 -1
  44. data/lib/hexapdf/content/parser.rb +22 -23
  45. data/lib/hexapdf/content/processor.rb +1 -1
  46. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  47. data/lib/hexapdf/content.rb +1 -1
  48. data/lib/hexapdf/data_dir.rb +1 -1
  49. data/lib/hexapdf/dictionary.rb +8 -2
  50. data/lib/hexapdf/dictionary_fields.rb +2 -2
  51. data/lib/hexapdf/digital_signature/cms_handler.rb +19 -2
  52. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  53. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +1 -1
  54. data/lib/hexapdf/digital_signature/signature.rb +2 -2
  55. data/lib/hexapdf/digital_signature/signatures.rb +1 -1
  56. data/lib/hexapdf/digital_signature/signing/default_handler.rb +3 -3
  57. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -2
  58. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +25 -5
  59. data/lib/hexapdf/digital_signature/signing.rb +1 -1
  60. data/lib/hexapdf/digital_signature/verification_result.rb +1 -1
  61. data/lib/hexapdf/digital_signature.rb +1 -1
  62. data/lib/hexapdf/document/annotations.rb +220 -0
  63. data/lib/hexapdf/document/destinations.rb +1 -1
  64. data/lib/hexapdf/document/files.rb +1 -1
  65. data/lib/hexapdf/document/fonts.rb +1 -1
  66. data/lib/hexapdf/document/images.rb +1 -1
  67. data/lib/hexapdf/document/layout.rb +95 -16
  68. data/lib/hexapdf/document/metadata.rb +11 -4
  69. data/lib/hexapdf/document/pages.rb +1 -1
  70. data/lib/hexapdf/document.rb +52 -9
  71. data/lib/hexapdf/encryption/aes.rb +1 -1
  72. data/lib/hexapdf/encryption/arc4.rb +3 -3
  73. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  74. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  75. data/lib/hexapdf/encryption/identity.rb +1 -1
  76. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  77. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  78. data/lib/hexapdf/encryption/security_handler.rb +4 -2
  79. data/lib/hexapdf/encryption/standard_security_handler.rb +40 -29
  80. data/lib/hexapdf/encryption.rb +1 -1
  81. data/lib/hexapdf/error.rb +12 -4
  82. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  83. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  84. data/lib/hexapdf/filter/crypt.rb +1 -1
  85. data/lib/hexapdf/filter/encryption.rb +1 -1
  86. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  87. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  88. data/lib/hexapdf/filter/pass_through.rb +1 -1
  89. data/lib/hexapdf/filter/predictor.rb +1 -1
  90. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  91. data/lib/hexapdf/filter.rb +1 -1
  92. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  93. data/lib/hexapdf/font/cmap/writer.rb +59 -5
  94. data/lib/hexapdf/font/cmap.rb +18 -7
  95. data/lib/hexapdf/font/encoding/base.rb +28 -1
  96. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  97. data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
  98. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  99. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  100. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  101. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  102. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
  103. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  104. data/lib/hexapdf/font/encoding.rb +1 -1
  105. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  106. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  107. data/lib/hexapdf/font/true_type/font.rb +1 -1
  108. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  109. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  110. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  111. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  112. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  113. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  114. data/lib/hexapdf/font/true_type/table/head.rb +1 -1
  115. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  116. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  117. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  118. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  119. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  120. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  121. data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
  122. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  123. data/lib/hexapdf/font/true_type/table.rb +7 -2
  124. data/lib/hexapdf/font/true_type.rb +1 -1
  125. data/lib/hexapdf/font/true_type_wrapper.rb +51 -16
  126. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  127. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  128. data/lib/hexapdf/font/type1/font.rb +1 -1
  129. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  130. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  131. data/lib/hexapdf/font/type1.rb +1 -1
  132. data/lib/hexapdf/font/type1_wrapper.rb +3 -4
  133. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  134. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  135. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  136. data/lib/hexapdf/font_loader/variant_from_name.rb +1 -1
  137. data/lib/hexapdf/font_loader.rb +1 -1
  138. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  139. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  140. data/lib/hexapdf/image_loader/png.rb +1 -1
  141. data/lib/hexapdf/image_loader.rb +1 -1
  142. data/lib/hexapdf/importer.rb +2 -2
  143. data/lib/hexapdf/layout/box.rb +6 -1
  144. data/lib/hexapdf/layout/box_fitter.rb +1 -1
  145. data/lib/hexapdf/layout/column_box.rb +1 -1
  146. data/lib/hexapdf/layout/container_box.rb +64 -29
  147. data/lib/hexapdf/layout/frame.rb +1 -1
  148. data/lib/hexapdf/layout/image_box.rb +1 -1
  149. data/lib/hexapdf/layout/inline_box.rb +1 -1
  150. data/lib/hexapdf/layout/line.rb +1 -1
  151. data/lib/hexapdf/layout/list_box.rb +1 -1
  152. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  153. data/lib/hexapdf/layout/page_style.rb +1 -1
  154. data/lib/hexapdf/layout/style.rb +133 -22
  155. data/lib/hexapdf/layout/table_box.rb +86 -14
  156. data/lib/hexapdf/layout/text_box.rb +1 -1
  157. data/lib/hexapdf/layout/text_fragment.rb +13 -2
  158. data/lib/hexapdf/layout/text_layouter.rb +1 -1
  159. data/lib/hexapdf/layout/text_shaper.rb +1 -1
  160. data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
  161. data/lib/hexapdf/layout.rb +1 -1
  162. data/lib/hexapdf/name_tree_node.rb +1 -1
  163. data/lib/hexapdf/number_tree_node.rb +1 -1
  164. data/lib/hexapdf/object.rb +4 -4
  165. data/lib/hexapdf/parser.rb +36 -7
  166. data/lib/hexapdf/pdf_array.rb +26 -4
  167. data/lib/hexapdf/rectangle.rb +1 -1
  168. data/lib/hexapdf/reference.rb +2 -2
  169. data/lib/hexapdf/revision.rb +7 -3
  170. data/lib/hexapdf/revisions.rb +1 -1
  171. data/lib/hexapdf/serializer.rb +8 -8
  172. data/lib/hexapdf/stream.rb +1 -1
  173. data/lib/hexapdf/task/dereference.rb +1 -1
  174. data/lib/hexapdf/task/merge_acro_form.rb +164 -0
  175. data/lib/hexapdf/task/optimize.rb +5 -5
  176. data/lib/hexapdf/task/pdfa.rb +1 -1
  177. data/lib/hexapdf/task.rb +2 -1
  178. data/lib/hexapdf/test_utils.rb +3 -2
  179. data/lib/hexapdf/tokenizer.rb +52 -44
  180. data/lib/hexapdf/type/acro_form/appearance_generator.rb +66 -13
  181. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  182. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  183. data/lib/hexapdf/type/acro_form/field.rb +6 -2
  184. data/lib/hexapdf/type/acro_form/form.rb +23 -32
  185. data/lib/hexapdf/type/acro_form/java_script_actions.rb +10 -3
  186. data/lib/hexapdf/type/acro_form/signature_field.rb +19 -8
  187. data/lib/hexapdf/type/acro_form/text_field.rb +10 -3
  188. data/lib/hexapdf/type/acro_form/variable_text_field.rb +13 -5
  189. data/lib/hexapdf/type/acro_form.rb +1 -1
  190. data/lib/hexapdf/type/action.rb +1 -1
  191. data/lib/hexapdf/type/actions/go_to.rb +2 -1
  192. data/lib/hexapdf/type/actions/go_to_r.rb +2 -1
  193. data/lib/hexapdf/type/actions/launch.rb +6 -2
  194. data/lib/hexapdf/type/actions/set_ocg_state.rb +1 -1
  195. data/lib/hexapdf/type/actions/uri.rb +1 -1
  196. data/lib/hexapdf/type/actions.rb +1 -1
  197. data/lib/hexapdf/type/annotation.rb +78 -3
  198. data/lib/hexapdf/type/annotations/appearance_generator.rb +426 -0
  199. data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
  200. data/lib/hexapdf/type/annotations/border_styling.rb +160 -0
  201. data/lib/hexapdf/type/annotations/circle.rb +65 -0
  202. data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
  203. data/lib/hexapdf/type/annotations/line.rb +334 -0
  204. data/lib/hexapdf/type/annotations/line_ending_styling.rb +208 -0
  205. data/lib/hexapdf/type/annotations/link.rb +1 -1
  206. data/lib/hexapdf/type/annotations/markup_annotation.rb +15 -3
  207. data/lib/hexapdf/type/annotations/polygon.rb +64 -0
  208. data/lib/hexapdf/type/annotations/polygon_polyline.rb +109 -0
  209. data/lib/hexapdf/type/annotations/polyline.rb +64 -0
  210. data/lib/hexapdf/type/annotations/square.rb +65 -0
  211. data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
  212. data/lib/hexapdf/type/annotations/text.rb +1 -1
  213. data/lib/hexapdf/type/annotations/widget.rb +56 -118
  214. data/lib/hexapdf/type/annotations.rb +13 -1
  215. data/lib/hexapdf/type/catalog.rb +5 -2
  216. data/lib/hexapdf/type/cid_font.rb +6 -3
  217. data/lib/hexapdf/type/cmap.rb +58 -0
  218. data/lib/hexapdf/type/embedded_file.rb +1 -1
  219. data/lib/hexapdf/type/file_specification.rb +18 -15
  220. data/lib/hexapdf/type/font.rb +1 -1
  221. data/lib/hexapdf/type/font_descriptor.rb +5 -4
  222. data/lib/hexapdf/type/font_simple.rb +4 -2
  223. data/lib/hexapdf/type/font_true_type.rb +3 -1
  224. data/lib/hexapdf/type/font_type0.rb +2 -2
  225. data/lib/hexapdf/type/font_type1.rb +19 -1
  226. data/lib/hexapdf/type/font_type3.rb +1 -2
  227. data/lib/hexapdf/type/form.rb +8 -5
  228. data/lib/hexapdf/type/graphics_state_parameter.rb +8 -5
  229. data/lib/hexapdf/type/icon_fit.rb +1 -1
  230. data/lib/hexapdf/type/image.rb +9 -5
  231. data/lib/hexapdf/type/info.rb +3 -3
  232. data/lib/hexapdf/type/mark_information.rb +3 -3
  233. data/lib/hexapdf/type/marked_content_reference.rb +59 -0
  234. data/lib/hexapdf/type/measure.rb +57 -0
  235. data/lib/hexapdf/type/metadata.rb +1 -1
  236. data/lib/hexapdf/type/names.rb +1 -1
  237. data/lib/hexapdf/type/namespace.rb +57 -0
  238. data/lib/hexapdf/type/object_reference.rb +57 -0
  239. data/lib/hexapdf/type/object_stream.rb +1 -1
  240. data/lib/hexapdf/type/optional_content_configuration.rb +2 -2
  241. data/lib/hexapdf/type/optional_content_group.rb +1 -1
  242. data/lib/hexapdf/type/optional_content_membership.rb +2 -2
  243. data/lib/hexapdf/type/optional_content_properties.rb +1 -1
  244. data/lib/hexapdf/type/outline.rb +1 -1
  245. data/lib/hexapdf/type/outline_item.rb +1 -1
  246. data/lib/hexapdf/type/output_intent.rb +1 -1
  247. data/lib/hexapdf/type/page.rb +6 -4
  248. data/lib/hexapdf/type/page_label.rb +1 -1
  249. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  250. data/lib/hexapdf/type/resources.rb +13 -9
  251. data/lib/hexapdf/type/struct_elem.rb +72 -0
  252. data/lib/hexapdf/type/struct_tree_root.rb +64 -0
  253. data/lib/hexapdf/type/trailer.rb +1 -1
  254. data/lib/hexapdf/type/viewer_preferences.rb +5 -4
  255. data/lib/hexapdf/type/xref_stream.rb +1 -1
  256. data/lib/hexapdf/type.rb +8 -1
  257. data/lib/hexapdf/utils/bit_field.rb +1 -1
  258. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  259. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  260. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  261. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  262. data/lib/hexapdf/utils/object_hash.rb +1 -1
  263. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  264. data/lib/hexapdf/utils/sorted_tree_node.rb +17 -4
  265. data/lib/hexapdf/utils.rb +1 -1
  266. data/lib/hexapdf/version.rb +2 -2
  267. data/lib/hexapdf/writer.rb +3 -2
  268. data/lib/hexapdf/xref_section.rb +25 -6
  269. data/lib/hexapdf.rb +1 -1
  270. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5-R5.pdf +43 -0
  271. data/test/data/standard-security-handler/nopwd-aes-256bit-V5-R5.pdf +44 -0
  272. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5-R5.pdf +43 -0
  273. data/test/data/standard-security-handler/userpwd-aes-256bit-V5-R5.pdf +0 -0
  274. data/test/hexapdf/common_tokenizer_tests.rb +7 -7
  275. data/test/hexapdf/content/test_graphics_state.rb +2 -3
  276. data/test/hexapdf/content/test_operator.rb +4 -5
  277. data/test/hexapdf/digital_signature/common.rb +6 -1
  278. data/test/hexapdf/digital_signature/signing/test_default_handler.rb +6 -1
  279. data/test/hexapdf/digital_signature/signing/test_timestamp_handler.rb +12 -0
  280. data/test/hexapdf/digital_signature/test_cms_handler.rb +25 -15
  281. data/test/hexapdf/digital_signature/test_handler.rb +2 -3
  282. data/test/hexapdf/digital_signature/test_pkcs1_handler.rb +1 -2
  283. data/test/hexapdf/digital_signature/test_signature.rb +7 -0
  284. data/test/hexapdf/digital_signature/test_signatures.rb +12 -7
  285. data/test/hexapdf/document/test_annotations.rb +75 -0
  286. data/test/hexapdf/document/test_layout.rb +38 -10
  287. data/test/hexapdf/document/test_metadata.rb +13 -1
  288. data/test/hexapdf/encryption/common.rb +1 -1
  289. data/test/hexapdf/encryption/test_aes.rb +1 -1
  290. data/test/hexapdf/encryption/test_arc4.rb +2 -2
  291. data/test/hexapdf/encryption/test_security_handler.rb +8 -6
  292. data/test/hexapdf/encryption/test_standard_security_handler.rb +7 -3
  293. data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
  294. data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
  295. data/test/hexapdf/filter/test_flate_decode.rb +2 -3
  296. data/test/hexapdf/font/cmap/test_writer.rb +73 -16
  297. data/test/hexapdf/font/encoding/test_base.rb +20 -0
  298. data/test/hexapdf/font/encoding/test_glyph_list.rb +1 -1
  299. data/test/hexapdf/font/test_true_type_wrapper.rb +31 -5
  300. data/test/hexapdf/font/test_type1_wrapper.rb +8 -1
  301. data/test/hexapdf/font/true_type/test_table.rb +12 -0
  302. data/test/hexapdf/layout/test_box.rb +8 -2
  303. data/test/hexapdf/layout/test_container_box.rb +34 -6
  304. data/test/hexapdf/layout/test_list_box.rb +7 -7
  305. data/test/hexapdf/layout/test_page_style.rb +1 -1
  306. data/test/hexapdf/layout/test_style.rb +46 -12
  307. data/test/hexapdf/layout/test_table_box.rb +66 -16
  308. data/test/hexapdf/layout/test_text_box.rb +0 -6
  309. data/test/hexapdf/layout/test_text_fragment.rb +3 -3
  310. data/test/hexapdf/layout/test_text_layouter.rb +4 -2
  311. data/test/hexapdf/task/test_merge_acro_form.rb +104 -0
  312. data/test/hexapdf/task/test_optimize.rb +3 -1
  313. data/test/hexapdf/test_composer.rb +15 -0
  314. data/test/hexapdf/test_dictionary.rb +15 -0
  315. data/test/hexapdf/test_dictionary_fields.rb +1 -0
  316. data/test/hexapdf/test_document.rb +26 -8
  317. data/test/hexapdf/test_filter.rb +1 -1
  318. data/test/hexapdf/test_importer.rb +7 -0
  319. data/test/hexapdf/test_object.rb +1 -1
  320. data/test/hexapdf/test_parser.rb +87 -18
  321. data/test/hexapdf/test_pdf_array.rb +36 -3
  322. data/test/hexapdf/test_revision.rb +27 -6
  323. data/test/hexapdf/test_revisions.rb +1 -1
  324. data/test/hexapdf/test_serializer.rb +4 -4
  325. data/test/hexapdf/test_stream.rb +1 -2
  326. data/test/hexapdf/test_tokenizer.rb +1 -1
  327. data/test/hexapdf/test_writer.rb +22 -8
  328. data/test/hexapdf/test_xref_section.rb +15 -0
  329. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +118 -26
  330. data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
  331. data/test/hexapdf/type/acro_form/test_field.rb +10 -0
  332. data/test/hexapdf/type/acro_form/test_form.rb +32 -9
  333. data/test/hexapdf/type/acro_form/test_java_script_actions.rb +21 -0
  334. data/test/hexapdf/type/acro_form/test_signature_field.rb +3 -1
  335. data/test/hexapdf/type/acro_form/test_text_field.rb +7 -1
  336. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +14 -1
  337. data/test/hexapdf/type/actions/test_launch.rb +6 -2
  338. data/test/hexapdf/type/annotations/test_appearance_generator.rb +608 -0
  339. data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
  340. data/test/hexapdf/type/annotations/test_border_styling.rb +114 -0
  341. data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
  342. data/test/hexapdf/type/annotations/test_line.rb +144 -0
  343. data/test/hexapdf/type/annotations/test_line_ending_styling.rb +42 -0
  344. data/test/hexapdf/type/annotations/test_polygon_polyline.rb +29 -0
  345. data/test/hexapdf/type/annotations/test_widget.rb +47 -81
  346. data/test/hexapdf/type/test_annotation.rb +58 -0
  347. data/test/hexapdf/type/test_font_type1.rb +20 -1
  348. data/test/hexapdf/type/test_form.rb +7 -1
  349. data/test/hexapdf/type/test_image.rb +1 -1
  350. data/test/hexapdf/type/test_page.rb +7 -1
  351. data/test/hexapdf/type/test_page_tree_node.rb +2 -2
  352. data/test/hexapdf/type/test_resources.rb +3 -1
  353. data/test/hexapdf/utils/test_sorted_tree_node.rb +18 -7
  354. data/test/test_helper.rb +7 -0
  355. metadata +69 -9
@@ -116,6 +116,18 @@ describe HexaPDF::Layout::TableBox::Cell do
116
116
  assert_equal(12, cell.preferred_height)
117
117
  end
118
118
 
119
+ it "respects the set minimum height of the cell" do
120
+ cell = create_cell(children: HexaPDF::Layout::Box.create(width: 20, height: 10), min_height: 30)
121
+ assert(cell.fit(100, 25, @frame).failure?)
122
+
123
+ assert(cell.fit(100, 100, @frame).success?)
124
+ assert_equal(30, cell.height)
125
+
126
+ cell = create_cell(children: HexaPDF::Layout::Box.create(width: 20, height: 20), min_height: 2)
127
+ assert(cell.fit(100, 100, @frame).success?)
128
+ assert_equal(32, cell.height)
129
+ end
130
+
119
131
  it "doesn't fit children that are too big" do
120
132
  cell = create_cell(children: HexaPDF::Layout::Box.create(width: 300, height: 20))
121
133
  assert(cell.fit(100, 100, @frame).failure?)
@@ -143,9 +155,6 @@ describe HexaPDF::Layout::TableBox::Cell do
143
155
  box.fit(100, 100, @frame)
144
156
  box.draw(@canvas, 10, 75)
145
157
  operators = [[:save_graphics_state],
146
- [:append_rectangle, [9.5, 74.5, 101.0, 38.0]],
147
- [:clip_path_non_zero],
148
- [:end_path],
149
158
  [:append_rectangle, [10.0, 75.0, 100.0, 37.0]],
150
159
  [:stroke_path],
151
160
  [:restore_graphics_state],
@@ -265,7 +274,7 @@ describe HexaPDF::Layout::TableBox::Cells do
265
274
  end
266
275
 
267
276
  it "sets the correct information on the created cells" do
268
- cells = create_cells([[:a, {col_span: 2, content: :b}],
277
+ cells = create_cells([[:a, {col_span: 2, content: :b, min_height: 30}],
269
278
  [{col_span: 2, row_span: 2, content: :c}, {row_span: 2, content: :d}]])
270
279
  assert_equal(0, cells[0, 0].row)
271
280
  assert_equal(0, cells[0, 0].column)
@@ -275,6 +284,7 @@ describe HexaPDF::Layout::TableBox::Cells do
275
284
  assert_equal(1, cells[0, 1].column)
276
285
  assert_equal(1, cells[0, 1].row_span)
277
286
  assert_equal(2, cells[0, 1].col_span)
287
+ assert_equal(30, cells[0, 1].instance_variable_get(:@min_height))
278
288
  assert_equal(1, cells[1, 0].row)
279
289
  assert_equal(0, cells[1, 0].column)
280
290
  assert_equal(2, cells[1, 0].row_span)
@@ -511,6 +521,58 @@ describe HexaPDF::Layout::TableBox do
511
521
  [0, 66, 39.75, 22], [39.75, 66, 39.75, 22], [79.5, 44, 39.75, 44], [119.25, 66, 39.75, 22]])
512
522
  end
513
523
 
524
+ describe "row spans" do
525
+ # ----------
526
+ # | a | b |
527
+ # | a | |
528
+ # | a |----|
529
+ # | a | c |
530
+ # | a | |
531
+ # ----------
532
+ it "works if content of a row span cell is larger than the rows" do
533
+ cells = [[{row_span: 2, content: @fixed_size_boxes[0..2]}, @fixed_size_boxes[3]],
534
+ [@fixed_size_boxes[4]]]
535
+ check_box(create_box(cells: cells, cell_style: {padding: 0, border: {width: 0}}),
536
+ :success, 160, 30,
537
+ [[0, 0, 80, 30], [80, 0, 80, 15], [0, 0, 80, 30], [80, 15, 80, 15]])
538
+ end
539
+
540
+ # ----------
541
+ # | a | b |
542
+ # | |----|
543
+ # | | c |
544
+ # ----------
545
+ it "works if content of a row span cell is smaller than the rows" do
546
+ cells = [[{row_span: 2, content: @fixed_size_boxes[0]}, @fixed_size_boxes[3]],
547
+ [@fixed_size_boxes[4]]]
548
+ check_box(create_box(cells: cells, cell_style: {padding: 0, border: {width: 0}}),
549
+ :success, 160, 20,
550
+ [[0, 0, 80, 20], [80, 0, 80, 10], [0, 0, 80, 20], [80, 10, 80, 10]])
551
+ end
552
+
553
+ # -----------------
554
+ # | a | b | c | d |
555
+ # | a | b |---| d |
556
+ # | a | b | e | |
557
+ # | a | | e | |
558
+ # --------| e | |
559
+ # | f | g | e | |
560
+ # ----------------
561
+ it "works if multiple, possibly overlapping row spans are involved" do
562
+ cells = [[{row_span: 2, content: @fixed_size_boxes[0..2]},
563
+ {row_span: 2, content: @fixed_size_boxes[3..4]},
564
+ @fixed_size_boxes[5],
565
+ {row_span: 3, content: @fixed_size_boxes[6..7]}],
566
+ [{row_span: 2, content: @fixed_size_boxes[8, 3]}],
567
+ [@fixed_size_boxes[11], @fixed_size_boxes[12]]]
568
+ check_box(create_box(cells: cells, cell_style: {padding: 0, border: {width: 0}}),
569
+ :success, 160, 40,
570
+ [[0, 0, 40, 30], [40, 0, 40, 30], [80, 0, 40, 10], [120, 0, 40, 40],
571
+ [0, 0, 40, 30], [40, 0, 40, 30], [80, 10, 40, 30], [120, 0, 40, 40],
572
+ [0, 30, 40, 10], [40, 30, 40, 10], [80, 10, 40, 30], [120, 0, 40, 40]])
573
+ end
574
+ end
575
+
514
576
  it "fits a table with header rows" do
515
577
  result = [[0, 0, 80, 10], [80, 0, 80, 10], [0, 10, 80, 10], [80, 10, 80, 10]]
516
578
  header = lambda {|_| [@fixed_size_boxes[10, 2], @fixed_size_boxes[12, 2]] }
@@ -622,9 +684,6 @@ describe HexaPDF::Layout::TableBox do
622
684
  box.fit(100, 100, @frame)
623
685
  box.draw(@canvas, 20, 10)
624
686
  operators = [[:save_graphics_state],
625
- [:append_rectangle, [20.0, 32.0, 50.5, 23.0]],
626
- [:clip_path_non_zero],
627
- [:end_path],
628
687
  [:append_rectangle, [20.5, 32.5, 49.5, 22.0]],
629
688
  [:stroke_path],
630
689
  [:restore_graphics_state],
@@ -634,9 +693,6 @@ describe HexaPDF::Layout::TableBox do
634
693
  [:end_path],
635
694
  [:restore_graphics_state],
636
695
  [:save_graphics_state],
637
- [:append_rectangle, [69.5, 32.0, 50.5, 23.0]],
638
- [:clip_path_non_zero],
639
- [:end_path],
640
696
  [:append_rectangle, [70.0, 32.5, 49.5, 22.0]],
641
697
  [:stroke_path],
642
698
  [:restore_graphics_state],
@@ -646,9 +702,6 @@ describe HexaPDF::Layout::TableBox do
646
702
  [:end_path],
647
703
  [:restore_graphics_state],
648
704
  [:save_graphics_state],
649
- [:append_rectangle, [20.0, 10.0, 50.5, 23.0]],
650
- [:clip_path_non_zero],
651
- [:end_path],
652
705
  [:append_rectangle, [20.5, 10.5, 49.5, 22.0]],
653
706
  [:stroke_path],
654
707
  [:restore_graphics_state],
@@ -658,9 +711,6 @@ describe HexaPDF::Layout::TableBox do
658
711
  [:end_path],
659
712
  [:restore_graphics_state],
660
713
  [:save_graphics_state],
661
- [:append_rectangle, [69.5, 10.0, 50.5, 23.0]],
662
- [:clip_path_non_zero],
663
- [:end_path],
664
714
  [:append_rectangle, [70.0, 10.5, 49.5, 22.0]],
665
715
  [:stroke_path],
666
716
  [:restore_graphics_state],
@@ -178,9 +178,6 @@ describe HexaPDF::Layout::TextBox do
178
178
  assert_operators(@canvas.contents, [[:save_graphics_state],
179
179
  [:restore_graphics_state],
180
180
  [:save_graphics_state],
181
- [:append_rectangle, [5, 10, 10, 10]],
182
- [:clip_path_non_zero],
183
- [:end_path],
184
181
  [:append_rectangle, [5.5, 10.5, 9.0, 9.0]],
185
182
  [:stroke_path],
186
183
  [:restore_graphics_state],
@@ -194,9 +191,6 @@ describe HexaPDF::Layout::TextBox do
194
191
  box.fit(60, 100, @frame)
195
192
  box.draw(@canvas, 40, 88)
196
193
  assert_operators(@canvas.contents, [[:save_graphics_state],
197
- [:append_rectangle, [40, 88, 12, 12]],
198
- [:clip_path_non_zero],
199
- [:end_path],
200
194
  [:append_rectangle, [40.5, 88.5, 11.0, 11.0]],
201
195
  [:stroke_path],
202
196
  [:restore_graphics_state],
@@ -139,7 +139,7 @@ describe HexaPDF::Layout::TextFragment do
139
139
  [:set_text_rise, [2]],
140
140
  *middle,
141
141
  [:begin_text],
142
- [:set_text_matrix, [1, 0, 0, 1, 10, 15]],
142
+ [:move_text, [10, 15]],
143
143
  [:show_text, ['!']],
144
144
  *back,
145
145
  ].compact
@@ -156,7 +156,7 @@ describe HexaPDF::Layout::TextFragment do
156
156
  @canvas = @doc.pages.add.canvas
157
157
  @fragment.draw(@canvas, 10, 15, ignore_text_properties: true)
158
158
  assert_operators(@canvas.contents, [[:begin_text],
159
- [:set_text_matrix, [1, 0, 0, 1, 10, 15]]])
159
+ [:move_text, [10, 15]]])
160
160
  end
161
161
 
162
162
  describe "uses an appropriate text position setter" do
@@ -188,7 +188,7 @@ describe HexaPDF::Layout::TextFragment do
188
188
  it "horizontal and vertical movement" do
189
189
  @fragment.draw(@canvas, 10, 10, ignore_text_properties: true)
190
190
  assert_operators(@canvas.contents, [[:begin_text],
191
- [:set_text_matrix, [1, 0, 0, 1, 10, 10]]])
191
+ [:move_text, [10, 10]]])
192
192
  end
193
193
  end
194
194
 
@@ -743,10 +743,12 @@ describe HexaPDF::Layout::TextLayouter do
743
743
  result = processor.recorded_ops
744
744
  leading = (result.select {|name, _| name == :set_leading } || [0]).map(&:last).flatten.first
745
745
  pos = [0, 0]
746
- result.select! {|name, _| name == :set_text_matrix || name == :move_text_next_line }.
747
- map! do |name, ops|
746
+ result.select! do |name, _|
747
+ name == :set_text_matrix || name == :move_text || name == :move_text_next_line
748
+ end.map! do |name, ops|
748
749
  case name
749
750
  when :set_text_matrix then pos = ops[-2, 2]
751
+ when :move_text then pos = ops
750
752
  when :move_text_next_line then pos[1] -= leading
751
753
  end
752
754
  pos.dup
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+ require 'hexapdf/task/merge_acro_form'
6
+
7
+ describe HexaPDF::Task::MergeAcroForm do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @doc.pages.add
11
+ @doc.pages.add
12
+ form = @doc.acro_form(create: true)
13
+ field = form.create_text_field("Text")
14
+ field.create_widget(@doc.pages[0], Rect: [0, 0, 0, 0])
15
+ field.create_widget(@doc.pages[1], Rect: [0, 0, 0, 0])
16
+
17
+ form.create_text_field("Calc.Field a")
18
+ form.create_text_field("Calc.Field b")
19
+ field = form.create_text_field('Other.Calculation 1')
20
+ field.set_calculate_action(:sum, fields: ["Calc.Field a", "Calc.Field b"])
21
+ field.create_widget(@doc.pages[1])
22
+ field = form.create_text_field('Other.Calculation 2')
23
+ field.set_calculate_action(:sfn, fields: "Calc.Field\\ a + Calc.Field\\ b")
24
+ field.create_widget(@doc.pages[1])
25
+
26
+ @root_fields = @doc.acro_form.root_fields
27
+
28
+ @doc.dispatch_message(:complete_objects)
29
+ @doc.validate
30
+ @doc1 = @doc.duplicate
31
+ @pages = []
32
+ @pages << @doc.pages.add(@doc.import(@doc1.pages[0]))
33
+ @pages << @doc.pages.add(@doc.import(@doc1.pages[1]))
34
+ end
35
+
36
+ it "selects a unique name for the root field" do
37
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
38
+ assert_equal('merged_1', @root_fields[3][:T])
39
+
40
+ @root_fields << @doc.wrap({T: 'merged_23'})
41
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
42
+ assert_equal('merged_24', @root_fields[5][:T])
43
+ end
44
+
45
+ it "merges the /DR entry of the main AcroForm dictionary" do
46
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
47
+ assert(@doc.acro_form.default_resources[:Font].key?(:F2))
48
+ end
49
+
50
+ it "updates the /SigFlags if necessary" do
51
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
52
+ refute(@doc.acro_form.signature_flag?(:signatures_exist))
53
+
54
+ @pages[0][:Annots][0].form_field[:FT] = :Sig
55
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
56
+ refute(@doc.acro_form.signature_flag?(:signatures_exist))
57
+
58
+ @doc1.acro_form.signature_flag(:signatures_exist)
59
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
60
+ assert(@doc.acro_form.signature_flag?(:signatures_exist))
61
+ end
62
+
63
+ it "applies the /DA and /Q entries of the source AcroForm to the created root field" do
64
+ @doc1.acro_form.set_default_appearance_string
65
+ @doc1.acro_form[:Q] = @doc1.add(5)
66
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
67
+ assert_equal('0.0 g /F2 0 Tf', @root_fields[3][:DA])
68
+ assert_equal(5, @root_fields[3][:Q])
69
+ end
70
+
71
+ it "merges only the fields references in the given pages" do
72
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
73
+ assert_equal('merged_1', @root_fields[3][:T])
74
+ assert_equal(1, @root_fields[3][:Kids].size)
75
+ end
76
+
77
+ it "only merges fields that have at least one widget" do
78
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
79
+ assert_equal(2, @root_fields[3][:Kids].size)
80
+ assert_nil(@doc.acro_form.field_by_name('merged_1.Calc'))
81
+ end
82
+
83
+ it "updates the /DA entries of widgets and fields" do
84
+ @pages[0][:Annots][0][:DA] = +'/F1 10 Tf'
85
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
86
+ field = @doc.acro_form.field_by_name('merged_1.Text')
87
+ assert_equal('0.0 g /F2 0 Tf', field[:DA])
88
+ assert_equal('/F2 10 Tf', field.each_widget.to_a[0][:DA])
89
+ end
90
+
91
+ it "doesn't update the calculation actions if no field with one is merged" do
92
+ @doc.task(:merge_acro_form, source: @doc1, pages: [@pages[0]])
93
+ assert_equal(2, @doc.acro_form[:CO].size)
94
+ end
95
+
96
+ it "updates the field names in known calculation actions" do
97
+ @doc.task(:merge_acro_form, source: @doc1, pages: @pages)
98
+ assert_equal(4, @doc.acro_form[:CO].size)
99
+ js = @doc.acro_form.field_by_name('merged_1.Other.Calculation 1')[:AA][:C][:JS]
100
+ assert_match(/merged_1.Calc.Field a/, js)
101
+ js = @doc.acro_form.field_by_name('merged_1.Other.Calculation 2')[:AA][:C][:JS]
102
+ assert_match(/merged_1.Calc.Field a/, js)
103
+ end
104
+ end
@@ -8,6 +8,7 @@ describe HexaPDF::Task::Optimize do
8
8
  class TestType < HexaPDF::Dictionary
9
9
 
10
10
  define_type :Test
11
+ define_field :Type, type: Symbol, default: type
11
12
  define_field :Optional, type: Symbol, default: :Optional
12
13
 
13
14
  end
@@ -46,6 +47,7 @@ describe HexaPDF::Task::Optimize do
46
47
  end
47
48
 
48
49
  def assert_default_deleted
50
+ assert(@doc.object(1).key?(:Type))
49
51
  refute(@doc.object(1).key?(:Optional))
50
52
  end
51
53
 
@@ -97,7 +99,7 @@ describe HexaPDF::Task::Optimize do
97
99
  objstm = @doc.add({}, type: HexaPDF::Type::ObjectStream)
98
100
  @doc.add({}, type: HexaPDF::Type::XRefStream)
99
101
  objstm.add_object(@doc.add({Type: :Test}))
100
- @doc.write(io)
102
+ @doc.write(io, compact: false)
101
103
  io.rewind
102
104
  @doc = HexaPDF::Document.new(io: io)
103
105
  end
@@ -63,6 +63,14 @@ describe HexaPDF::Composer do
63
63
  end
64
64
  end
65
65
 
66
+ it "writes the document to a string" do
67
+ pdf = HexaPDF::Composer.new
68
+ pdf.new_page
69
+ str = pdf.write_to_string
70
+ doc = HexaPDF::Document.new(io: StringIO.new(str))
71
+ assert_equal(2, doc.pages.count)
72
+ end
73
+
66
74
  describe "new_page" do
67
75
  it "creates a new page" do
68
76
  c = HexaPDF::Composer.new(page_size: [0, 0, 50, 100], margin: 10)
@@ -119,6 +127,13 @@ describe HexaPDF::Composer do
119
127
  end
120
128
  end
121
129
 
130
+ describe "style?" do
131
+ it "delegates to layout.style?" do
132
+ @composer.document.layout.style(:header, font_size: 20)
133
+ assert(@composer.style?(:header))
134
+ end
135
+ end
136
+
122
137
  describe "styles" do
123
138
  it "delegates to layout.styles" do
124
139
  @composer.styles(base: {font_size: 30}, other: {font_size: 40})
@@ -251,8 +251,23 @@ describe HexaPDF::Dictionary do
251
251
  refute(@obj.validate(auto_correct: false))
252
252
  assert(@obj.validate(auto_correct: true))
253
253
  @obj.value[:NameField] = "string"
254
+ refute(@obj.validate(auto_correct: false))
254
255
  assert(@obj.validate(auto_correct: true))
256
+
257
+ @test_class.define_field(:RequiredDefault, type: String, required: true, default: 'str')
258
+ @obj.value[:RequiredDefault] = 20
259
+ refute(@obj.validate(auto_correct: false))
260
+ assert_equal(20, @obj.value[:RequiredDefault])
255
261
  assert(@obj.validate(auto_correct: true))
262
+ assert_equal("str", @obj.value[:RequiredDefault])
263
+
264
+ @obj.value[:AllowedValues] = '20'
265
+ assert(@obj.validate(auto_correct: true))
266
+ refute(@obj.key?(:AllowedValues))
267
+
268
+ @obj.value[:Inherited] = 20
269
+ refute(@obj.validate(auto_correct: true))
270
+ refute(@obj.key?(:Inherited))
256
271
  end
257
272
 
258
273
  it "checks whether the value is an allowed one" do
@@ -193,6 +193,7 @@ describe HexaPDF::DictionaryFields do
193
193
  ["D:19981223195210Z00'00", [1998, 12, 23, 19, 52, 10, "+00:00"]],
194
194
  ["D:19981223195210-08", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
195
195
  ["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], # no trailing ', as per PDF 2.0
196
+ ["D:19981223195210-08'00''", [1998, 12, 23, 19, 52, 10, "-08:00"]], # two trailing '
196
197
  ["D:19981223195210-54'00", [1998, 12, 23, 19, 52, 10, "-23:59:59"]], # TZ hour too large
197
198
  ["D:19981223195210+10'65", [1998, 12, 23, 19, 52, 10, "+11:05"]], # TZ min too large
198
199
  ["D:19982423195210-08'00'", [1998, 12, 23, 19, 52, 10, "-08:00"]], # months too large
@@ -54,7 +54,7 @@ describe HexaPDF::Document do
54
54
  describe "::open" do
55
55
  before do
56
56
  @file = Tempfile.new('hexapdf-document')
57
- @io_doc.write(@file)
57
+ @io_doc.write(@file, compact: false)
58
58
  @file.close
59
59
  end
60
60
 
@@ -347,7 +347,7 @@ describe HexaPDF::Document do
347
347
 
348
348
  it "validates the trailer object" do
349
349
  @doc.trailer[:ID] = :Symbol
350
- refute(@doc.validate {|_, _, obj| assert_same(@doc.trailer, obj) })
350
+ assert(@doc.validate {|_a, _b, obj| assert_same(@doc.trailer, obj) })
351
351
  end
352
352
 
353
353
  it "validates only loaded objects" do
@@ -370,7 +370,7 @@ describe HexaPDF::Document do
370
370
  it "writes the document to a file" do
371
371
  file = Tempfile.new('hexapdf-write')
372
372
  file.close
373
- @io_doc.write(file.path)
373
+ @io_doc.write(file.path, compact: false)
374
374
  HexaPDF::Document.open(file.path) do |doc|
375
375
  assert_equal(200, doc.object(2).value)
376
376
  end
@@ -391,7 +391,7 @@ describe HexaPDF::Document do
391
391
  end
392
392
 
393
393
  it "fails if the document is not valid" do
394
- @doc.trailer[:Size] = :Symbol
394
+ @doc.catalog[:PageLayout] = :invalid_value
395
395
  assert_raises(HexaPDF::Error) { @doc.write(StringIO.new(''.b)) }
396
396
  end
397
397
 
@@ -422,10 +422,18 @@ describe HexaPDF::Document do
422
422
 
423
423
  it "allows optimizing the file by using object streams" do
424
424
  io = StringIO.new(''.b)
425
- @io_doc.write(io, optimize: true)
425
+ @io_doc.write(io, optimize: true, compact: false)
426
426
  doc = HexaPDF::Document.new(io: io)
427
427
  assert_equal(2, doc.each.count {|o| o.type == :ObjStm })
428
428
  end
429
+
430
+ it "automatically compacts the file" do
431
+ io = StringIO.new(''.b)
432
+ @io_doc.write(io)
433
+ doc = HexaPDF::Document.new(io: io)
434
+ assert_equal(1, doc.revisions.count)
435
+ assert_equal(4, doc.each.count)
436
+ end
429
437
  end
430
438
 
431
439
  describe "version" do
@@ -497,10 +505,10 @@ describe HexaPDF::Document do
497
505
 
498
506
  it "returns all signature fields of the document" do
499
507
  form = @doc.acro_form(create: true)
500
- sig1 = @doc.add({FT: :Sig, T: 'sig1', V: :sig1})
501
- sig2 = @doc.add({FT: :Sig, T: 'sig2', V: :sig2})
508
+ sig1 = @doc.add({FT: :Sig, T: 'sig1', V: {k: :sig1}})
509
+ sig2 = @doc.add({FT: :Sig, T: 'sig2', V: {k: :sig2}})
502
510
  form.root_fields << sig1 << sig2
503
- assert_equal([:sig1, :sig2], @doc.signatures.to_a)
511
+ assert_equal([{k: :sig1}, {k: :sig2}], @doc.signatures.to_a)
504
512
  end
505
513
 
506
514
  it "allows to conveniently sign a document" do
@@ -595,4 +603,14 @@ describe HexaPDF::Document do
595
603
  refute(dupped.encrypted?)
596
604
  end
597
605
  end
606
+
607
+ it "writes the document to a string" do
608
+ doc = HexaPDF::Document.new
609
+ doc.trailer.info[:test] = :test
610
+ str = doc.write_to_string(update_fields: false)
611
+ assert_equal(Encoding::ASCII_8BIT, str.encoding)
612
+ doc = HexaPDF::Document.new(io: StringIO.new(str))
613
+ assert_equal(:test, doc.trailer.info[:test])
614
+ assert_nil(doc.trailer.info[:ModDate])
615
+ end
598
616
  end
@@ -8,7 +8,7 @@ require 'tempfile'
8
8
  describe HexaPDF::Filter do
9
9
  before do
10
10
  @obj = HexaPDF::Filter
11
- @str = ''
11
+ @str = +''
12
12
  40.times { @str << [rand(2**32)].pack('N') }
13
13
  end
14
14
 
@@ -147,6 +147,13 @@ describe HexaPDF::Importer do
147
147
  assert_nil(obj[:pages])
148
148
  end
149
149
 
150
+ it "handles null values correctly" do
151
+ @source.add(@hash)
152
+ @source.delete(@hash)
153
+ obj = @importer.import(@obj)
154
+ assert_nil(obj[:hash])
155
+ end
156
+
150
157
  it "imports Page objects correctly by copying the inherited values" do
151
158
  page = @importer.import(@source.pages[0])
152
159
  assert_equal(90, page[:Rotate])
@@ -197,7 +197,7 @@ describe HexaPDF::Object do
197
197
  @obj.define_singleton_method(:perform_validation) { raise "Unknown" }
198
198
  invoked = []
199
199
  refute(@obj.validate {|*a| invoked << a })
200
- assert_equal([["Error: Unexpected value encountered", false, @obj]], invoked)
200
+ assert_equal([["Unexpected error encountered: Unknown", false, @obj]], invoked)
201
201
  end
202
202
  end
203
203