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
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -134,11 +134,12 @@ module HexaPDF
134
134
  if !normal_appearance.kind_of?(HexaPDF::Dictionary) || normal_appearance.kind_of?(HexaPDF::Stream)
135
135
  (@widget[:AP] ||= {})[:N] = {Off: nil}
136
136
  normal_appearance = @widget[:AP][:N]
137
- normal_appearance[@field[:V] == :Off ? :Yes : @field[:V]] = nil
137
+ normal_appearance[@field.field_value&.to_sym || :Yes] = nil
138
138
  end
139
139
  on_name = (normal_appearance.value.keys - [:Off]).first
140
140
  unless on_name
141
- raise HexaPDF::Error, "Widget of button field doesn't define name for on state"
141
+ on_name = @field.field_value&.to_sym || :Yes
142
+ normal_appearance[on_name] = nil
142
143
  end
143
144
 
144
145
  @widget[:AS] = (@field[:V] == on_name ? on_name : :Off)
@@ -173,11 +174,59 @@ module HexaPDF
173
174
 
174
175
  alias create_radio_button_appearances create_check_box_appearances
175
176
 
176
- # Creates the appropriate appearances for push buttons.
177
+ # Creates the appropriate appearances for push button fields
177
178
  #
178
- # This is currently a dummy implementation raising an error.
179
+ # The following describes how the appearance is built:
180
+ #
181
+ # * The widget's rectangle /Rect must be defined.
182
+ #
183
+ # * If the font size (used for the caption) is zero, a font size of
184
+ # +acro_form.default_font_size+ is used.
185
+ #
186
+ # * The line width, style and color of the rectangle are taken from the widget's border
187
+ # style. See HexaPDF::Type::Annotations::Widget#border_style.
188
+ #
189
+ # * The background color is determined by the widget's background color. See
190
+ # HexaPDF::Type::Annotations::Widget#background_color.
179
191
  def create_push_button_appearances
180
- raise HexaPDF::Error, "Push button appearance generation not yet supported"
192
+ default_resources = @document.acro_form(create: true).default_resources
193
+ border_style = @widget.border_style
194
+ padding = border_style.width
195
+ marker_style = @widget.marker_style
196
+ font = retrieve_font_information(marker_style.font_name, default_resources)
197
+
198
+ @widget[:AS] = :N
199
+ @widget.flag(:print)
200
+ @widget.unflag(:hidden)
201
+ rect = @widget[:Rect]
202
+
203
+ width, height, matrix = perform_rotation(rect.width, rect.height)
204
+
205
+ form = (@widget[:AP] ||= {})[:N] ||= @document.add({Type: :XObject, Subtype: :Form})
206
+ # Wrap existing object in Form class in case the PDF writer didn't include the /Subtype
207
+ # key or the type of the object is wrong; we can do this since we know this has to be a
208
+ # Form object
209
+ unless form.type == :XObject && form[:Subtype] == :Form
210
+ form = @document.wrap(form, type: :XObject, subtype: :Form)
211
+ end
212
+ form.value.replace({Type: :XObject, Subtype: :Form, BBox: [0, 0, width, height],
213
+ Matrix: matrix, Resources: HexaPDF::Object.deep_copy(default_resources)})
214
+ form.contents = ''
215
+
216
+ canvas = form.canvas
217
+ apply_background_and_border(border_style, canvas)
218
+
219
+ style = HexaPDF::Layout::Style.new(font: font, font_size: marker_style.size,
220
+ fill_color: marker_style.color)
221
+ if (text = marker_style.style) && text.kind_of?(String)
222
+ items = @document.layout.text_fragments(marker_style.style, style: style)
223
+ layouter = Layout::TextLayouter.new(style)
224
+ layouter.style.text_align(:center).text_valign(:center).line_spacing(:proportional, 1.25)
225
+ result = layouter.fit(items, width - 2 * padding, height - 2 * padding)
226
+ unless result.lines.empty?
227
+ result.draw(canvas, padding, height - padding)
228
+ end
229
+ end
181
230
  end
182
231
 
183
232
  # Creates the appropriate appearances for text fields, combo box fields and list box fields.
@@ -206,7 +255,8 @@ module HexaPDF
206
255
  # Note: Rich text fields are currently not supported!
207
256
  def create_text_appearances
208
257
  default_resources = @document.acro_form.default_resources
209
- font, font_size, font_color = retrieve_font_information(default_resources)
258
+ font_name, font_size, font_color = @field.parse_default_appearance_string(@widget)
259
+ font = retrieve_font_information(font_name, default_resources)
210
260
  style = HexaPDF::Layout::Style.new(font: font, font_size: font_size, fill_color: font_color)
211
261
  border_style = @widget.border_style
212
262
  padding = [1, border_style.width].max
@@ -226,8 +276,11 @@ module HexaPDF
226
276
 
227
277
  form = (@widget[:AP] ||= {})[:N] ||= @document.add({Type: :XObject, Subtype: :Form})
228
278
  # Wrap existing object in Form class in case the PDF writer didn't include the /Subtype
229
- # key; we can do this since we know this has to be a Form object
230
- form = @document.wrap(form, type: :XObject, subtype: :Form) unless form[:Subtype] == :Form
279
+ # key or the type of the object is wrong; we can do this since we know this has to be a
280
+ # Form object
281
+ unless form.type == :XObject && form[:Subtype] == :Form
282
+ form = @document.wrap(form, type: :XObject, subtype: :Form)
283
+ end
231
284
  form.value.replace({Type: :XObject, Subtype: :Form, BBox: [0, 0, width, height],
232
285
  Matrix: matrix, Resources: HexaPDF::Object.deep_copy(default_resources)})
233
286
  form.contents = ''
@@ -471,9 +524,9 @@ module HexaPDF
471
524
  end
472
525
  end
473
526
 
474
- # Returns the font wrapper and font size to be used for a variable text field.
475
- def retrieve_font_information(resources)
476
- font_name, font_size, font_color = @field.parse_default_appearance_string(@widget)
527
+ # Returns the font wrapper, font size and font color to be used for variable text fields and
528
+ # push button captions.
529
+ def retrieve_font_information(font_name, resources)
477
530
  font_object = resources.font(font_name) rescue nil
478
531
  font = font_object&.font_wrapper
479
532
  unless font
@@ -489,7 +542,7 @@ module HexaPDF
489
542
  raise(HexaPDF::Error, "Font #{font_name} of the AcroForm's default resources not usable")
490
543
  end
491
544
  end
492
- [font, font_size, font_color]
545
+ font
493
546
  end
494
547
 
495
548
  # Calculates the font size for single line text fields using auto-sizing, based on the font
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -291,7 +291,10 @@ module HexaPDF
291
291
  if embedded_widget?
292
292
  yield(document.wrap(self))
293
293
  elsif terminal_field?
294
- self[:Kids]&.each {|kid| yield(document.wrap(kid)) }
294
+ self[:Kids]&.each do |kid|
295
+ kid = document.wrap(kid)
296
+ yield(kid) if kid.type == :Annot && kid[:Subtype] == :Widget
297
+ end
295
298
  end
296
299
 
297
300
  unless direct_only
@@ -392,6 +395,7 @@ module HexaPDF
392
395
  break # Each annotation dictionary may only appear on one page, see PDF2.0 12.5.2
393
396
  end
394
397
  end
398
+ document.revisions.current.update(self)
395
399
  widget
396
400
  end
397
401
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -81,6 +81,7 @@ module HexaPDF
81
81
  define_field :CO, type: PDFArray, version: '1.3'
82
82
  define_field :DR, type: :XXResources
83
83
  define_field :DA, type: String
84
+ define_field :Q, type: Integer
84
85
  define_field :XFA, type: [Stream, PDFArray], version: '1.5'
85
86
 
86
87
  bit_field(:signature_flags, {signatures_exist: 0, append_only: 1},
@@ -182,24 +183,18 @@ module HexaPDF
182
183
  # The optional keyword arguments allow setting often used properties of the field:
183
184
  #
184
185
  # +font+::
185
- # The font that should be used for the text of the field. If +font_size+, +font_options+
186
- # or +font_color+ is specified but +font+ isn't, the font Helvetica is used.
187
- #
188
- # If no font is set on the text field, the default font properties of the AcroForm form
189
- # are used. Note that field specific or form specific font properties have to be set.
190
- # Otherwise there will be an error when trying to generate a visual representation of
191
- # the field value.
186
+ # The font that should be used for the text of the field. If not specified, it
187
+ # defaults to Helvetica.
192
188
  #
193
189
  # +font_options+::
194
- # A hash with font options like :variant that should be used.
190
+ # A hash with font options like :variant that should be used. If not specified, it
191
+ # defaults to the empty hash.
195
192
  #
196
193
  # +font_size+::
197
- # The font size that should be used. If +font+, +font_options+ or +font_color+ is
198
- # specified but +font_size+ isn't, font size defaults to 0 (= auto-sizing).
194
+ # The font size that should be used. If not specified, it defaults to 0 (= auto-sizing).
199
195
  #
200
196
  # +font_color+::
201
- # The font color that should be used. If +font+, +font_options+ or +font_size+ is
202
- # specified but +font_color+ isn't, font color defaults to 0 (i.e. black).
197
+ # The font color that should be used. If not specified, it defaults to 0 (i.e. black).
203
198
  #
204
199
  # +align+::
205
200
  # The alignment of the text, either :left, :center or :right.
@@ -440,8 +435,7 @@ module HexaPDF
440
435
 
441
436
  # Returns the dictionary containing the default resources for form field appearance streams.
442
437
  def default_resources
443
- self[:DR] ||= document.wrap({ProcSet: [:PDF, :Text, :ImageB, :ImageC, :ImageI]},
444
- type: :XXResources)
438
+ self[:DR] ||= document.wrap({}, type: :XXResources)
445
439
  end
446
440
 
447
441
  # Sets the global default appearance string using the provided values or the default values
@@ -523,11 +517,11 @@ module HexaPDF
523
517
  #
524
518
  # See: JavaScriptActions
525
519
  def recalculate_fields
526
- self[:CO]&.each do |field|
520
+ (each_field.to_a & self[:CO].to_a).each do |field|
527
521
  field = Field.wrap(document, field)
528
522
  next unless field && (calculation_action = field[:AA]&.[](:C))
529
523
  result = JavaScriptActions.calculate(self, calculation_action)
530
- field.form_field.field_value = result if result
524
+ field.field_value = result if result
531
525
  end
532
526
  end
533
527
 
@@ -561,13 +555,11 @@ module HexaPDF
561
555
  # Applies the given variable field properties to the field.
562
556
  def apply_variable_text_properties(field, font: nil, font_options: nil, font_size: nil,
563
557
  font_color: nil, align: nil)
564
- if font || font_options || font_size || font_color
565
- field.set_default_appearance_string(font: font || 'Helvetica',
566
- font_options: font_options || {},
567
- font_size: font_size || 0,
568
- font_color: font_color || 0)
569
- end
570
- field.text_alignment(align) if align
558
+ field.set_default_appearance_string(font: font || 'Helvetica',
559
+ font_options: font_options || {},
560
+ font_size: font_size || 0,
561
+ font_color: font_color || 0)
562
+ field.text_alignment(align || :left)
571
563
  end
572
564
 
573
565
  def perform_validation # :nodoc:
@@ -576,12 +568,12 @@ module HexaPDF
576
568
  seen = {} # used for combining field
577
569
 
578
570
  validate_array = lambda do |parent, container|
579
- container.reject! do |field|
571
+ container.map! do |field|
580
572
  if !field.kind_of?(HexaPDF::Object) || !field.kind_of?(HexaPDF::Dictionary) || field.null?
581
573
  yield("Invalid object in AcroForm field hierarchy", true)
582
- next true
574
+ next nil
583
575
  end
584
- next false unless field.key?(:T) # Skip widgets
576
+ next field unless field.key?(:T) # Skip widgets
585
577
 
586
578
  field = Field.wrap(document, field)
587
579
  reject = false
@@ -605,14 +597,15 @@ module HexaPDF
605
597
  widget[:Parent] = other_field
606
598
  kids << widget
607
599
  end
600
+ document.delete(field)
608
601
  reject = true
609
602
  elsif !reject
610
603
  seen[name] = field
611
604
  end
612
605
 
613
- validate_array.call(field, field[:Kids]) if field.key?(:Kids)
614
- reject
615
- end
606
+ validate_array.call(field, field[:Kids]) if !field.null? && field.key?(:Kids)
607
+ reject ? nil : field
608
+ end.compact!
616
609
  end
617
610
  validate_array.call(nil, root_fields)
618
611
 
@@ -625,8 +618,6 @@ module HexaPDF
625
618
  if font_name && !(self[:DR][:Font] && self[:DR][:Font][font_name])
626
619
  yield("The font specified in /DA is not in the /DR resource dictionary")
627
620
  end
628
- else
629
- set_default_appearance_string
630
621
  end
631
622
 
632
623
  create_appearances if document.config['acro_form.create_appearances']
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -496,7 +496,7 @@ module HexaPDF
496
496
  else
497
497
  nil
498
498
  end
499
- result && (result == result.truncate ? result.to_i.to_s : result.to_s)
499
+ result && (result.finite? && result == result.truncate ? result.to_i.to_s : result.to_s)
500
500
  end
501
501
 
502
502
  AF_SIMPLE_CALCULATE_MAPPING = { #:nodoc:
@@ -613,7 +613,14 @@ module HexaPDF
613
613
 
614
614
  # Returns the numeric value of the string, interpreting comma as point.
615
615
  def af_make_number(value)
616
- value.to_s.tr(',', '.').to_f
616
+ value = value.to_s
617
+ if value.match?(/(?:[+-])?Inf(?:inity)?/i)
618
+ value.start_with?('-') ? -Float::INFINITY : Float::INFINITY
619
+ elsif value.match?(/NaN/i)
620
+ Float::NAN
621
+ else
622
+ value.tr(',', '.').to_f
623
+ end
617
624
  end
618
625
 
619
626
  # Formats the numeric value according to the format string and separator style.
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -62,8 +62,10 @@ module HexaPDF
62
62
 
63
63
  define_field :Type, type: Symbol, default: type
64
64
  define_field :Action, type: Symbol, required: true,
65
- allowed_values: [:All, :Include, :Exclude]
65
+ allowed_values: [:All, :Include, :Exclude]
66
66
  define_field :Fields, type: PDFArray
67
+ define_field :P, type: Numeric, version: '2.0',
68
+ allowed_values: [1, 2, 3]
67
69
 
68
70
  private
69
71
 
@@ -83,8 +85,8 @@ module HexaPDF
83
85
  # If a flag is set it means that the associated entry is a required constraint. Otherwise it
84
86
  # is optional.
85
87
  #
86
- # The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info
87
- # and digest_method.
88
+ # The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info,
89
+ # digest_method, lock_document and appearance_filter.
88
90
  #
89
91
  # See: PDF2.0 s12.7.5.5
90
92
  class SeedValueDictionary < Dictionary
@@ -98,13 +100,16 @@ module HexaPDF
98
100
  define_field :Filter, type: Symbol
99
101
  define_field :SubFilter, type: PDFArray
100
102
  define_field :DigestMethod, type: PDFArray, version: '1.7'
101
- define_field :V, type: Float
103
+ define_field :V, type: Integer
102
104
  define_field :Cert, type: :SVCert
103
105
  define_field :Reasons, type: PDFArray
104
106
  define_field :MDP, type: Dictionary, version: '1.6'
105
107
  define_field :TimeStamp, type: Dictionary, version: '1.6'
106
108
  define_field :LegalAttestation, type: PDFArray, version: '1.6'
107
109
  define_field :AddRevInfo, type: Boolean, version: '1.7'
110
+ define_field :LockDocument, type: Symbol, version: '2.0',
111
+ allowed_values: [:true, :false, :auto]
112
+ define_field :AppearanceFilter, type: String, version: '2.0'
108
113
 
109
114
  ##
110
115
  # :method: flags
@@ -130,7 +135,8 @@ module HexaPDF
130
135
  # all prior flags will be cleared.
131
136
  #
132
137
  bit_field(:flags, {filter: 0, sub_filter: 1, v: 2, reasons: 3, legal_attestation: 4,
133
- add_rev_info: 5, digest_method: 6},
138
+ add_rev_info: 5, digest_method: 6, lock_document: 7,
139
+ appearance_filter: 8},
134
140
  lister: "flags", getter: "flagged?", setter: "flag", unsetter: "unflag",
135
141
  value_getter: "self[:Ff]", value_setter: "self[:Ff]")
136
142
 
@@ -155,12 +161,16 @@ module HexaPDF
155
161
  define_field :Type, type: Symbol, default: type
156
162
  define_field :Ff, type: Integer, default: 0
157
163
  define_field :Subject, type: PDFArray
164
+ define_field :SignaturePolicyOID, type: String, version: '2.0'
165
+ define_field :SignaturePolicyHashValue, type: String, version: '2.0'
166
+ define_field :SignaturePolicyHashAlgorithm, type: Symbol, version: '2.0'
167
+ define_field :SignaturePolicyCommitmentType, type: PDFArray, version: '2.0'
158
168
  define_field :SubjectDN, type: PDFArray, version: '1.7'
159
169
  define_field :KeyUsage, type: PDFArray, version: '1.7'
160
170
  define_field :Issuer, type: PDFArray
161
171
  define_field :OID, type: PDFArray
162
172
  define_field :URL, type: String
163
- define_field :URLType, type: Symbol, default: :Browser
173
+ define_field :URLType, type: Symbol, default: :Browser, version: '1.7'
164
174
 
165
175
  ##
166
176
  # :method: flags
@@ -199,7 +209,8 @@ module HexaPDF
199
209
 
200
210
  # Returns the associated signature dictionary or +nil+ if the signature is not filled in.
201
211
  def field_value
202
- self[:V]
212
+ val = self[:V]
213
+ val.instance_of?(Dictionary) ? document.wrap(val, type: :Sig) : val
203
214
  end
204
215
 
205
216
  # Sets the signature dictionary as value of this signature field.
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -176,7 +176,7 @@ module HexaPDF
176
176
  end
177
177
  str = str.gsub(/[[:space:]]/, ' ') if str && concrete_field_type == :single_line_text_field
178
178
  if key?(:MaxLen) && str && str.length > self[:MaxLen]
179
- raise HexaPDF::Error, "Value exceeds maximum allowed length of #{self[:MaxLen]}"
179
+ str = @document.config['acro_form.text_field.on_max_len_exceeded'].call(self, str)
180
180
  end
181
181
  self[:V] = str
182
182
  update_widgets
@@ -348,7 +348,14 @@ module HexaPDF
348
348
  return
349
349
  end
350
350
  if (max_len = self[:MaxLen]) && field_value && field_value.length > max_len
351
- yield("Text contents of field '#{full_field_name}' is too long")
351
+ correctable = true
352
+ begin
353
+ str = @document.config['acro_form.text_field.on_max_len_exceeded'].call(self, field_value)
354
+ rescue HexaPDF::Error
355
+ correctable = false
356
+ end
357
+ yield("Text contents of field '#{full_field_name}' is too long", correctable)
358
+ self.field_value = str if correctable
352
359
  end
353
360
  if comb_text_field? && !max_len
354
361
  yield("Comb text field needs a value for /MaxLen")
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -51,7 +51,7 @@ module HexaPDF
51
51
  # See: PDF2.0 s12.7.4.3
52
52
  class VariableTextField < Field
53
53
 
54
- define_field :DA, type: String
54
+ define_field :DA, type: PDFByteString
55
55
  define_field :Q, type: Integer, default: 0, allowed_values: [0, 1, 2]
56
56
  define_field :DS, type: String, version: '1.5'
57
57
  define_field :RV, type: [String, Stream], version: '1.5'
@@ -106,7 +106,7 @@ module HexaPDF
106
106
  font_params[2] = HexaPDF::Content::ColorSpace.prenormalized_device_color(params)
107
107
  end
108
108
  end
109
- HexaPDF::Content::Parser.parse(appearance_string.sub(/\/\//, '/'), &block)
109
+ HexaPDF::Content::Parser.parse(appearance_string.to_s.sub(/\/\//, '/'), &block)
110
110
  block_given? ? nil : font_params
111
111
  end
112
112
 
@@ -154,13 +154,21 @@ module HexaPDF
154
154
  # font_size, font_color].
155
155
  #
156
156
  # The default appearance string is taken from the given +widget+ of the field, falls back to
157
- # the field itself or, if still not available, the default appearance string of the form.
157
+ # the field itself and then the default appearance string of the form. If it still not
158
+ # available, a standard default appearance string is set (see
159
+ # #set_default_appearance_string) and used.
158
160
  #
159
161
  # The reason why a specific widget of the field can be specified is because the widgets of a
160
162
  # field might differ in their visual representation.
161
163
  def parse_default_appearance_string(widget = self)
162
164
  da = widget[:DA] || self[:DA] || (document.acro_form && document.acro_form[:DA])
163
- raise HexaPDF::Error, "No default appearance string set" unless da
165
+ unless da
166
+ if (args = document.config['acro_form.fallback_default_appearance'])
167
+ da = set_default_appearance_string(**args)
168
+ else
169
+ raise HexaPDF::Error, "No default appearance string set"
170
+ end
171
+ end
164
172
  self.class.parse_appearance_string(da)
165
173
  end
166
174
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -47,6 +47,7 @@ module HexaPDF
47
47
 
48
48
  define_field :S, type: Symbol, required: true, default: :GoTo
49
49
  define_field :D, type: [Symbol, PDFByteString, PDFArray], required: true
50
+ define_field :SD, type: PDFArray, version: '2.0'
50
51
 
51
52
  end
52
53
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -48,6 +48,7 @@ module HexaPDF
48
48
  define_field :S, type: Symbol, required: true, default: :GoToR
49
49
  define_field :F, type: :Filespec, required: true
50
50
  define_field :D, type: [Symbol, PDFByteString, PDFArray], required: true
51
+ define_field :SD, type: PDFArray, version: '2.0'
51
52
  define_field :NewWindow, type: Boolean, version: '1.2'
52
53
 
53
54
  end
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -60,13 +60,17 @@ module HexaPDF
60
60
  define_field :S, type: Symbol, required: true, default: :Launch
61
61
  define_field :F, type: :Filespec
62
62
  define_field :Win, type: :XXLaunchActionWinParameters
63
+ define_field :Mac, type: ::Object, version: '2.0'
64
+ define_field :Unix, type: ::Object, version: '2.0'
63
65
  define_field :NewWindow, type: Boolean, version: '1.2'
64
66
 
65
67
  private
66
68
 
67
69
  def perform_validation #:nodoc:
68
70
  super
69
- yield("A Launch action needs a target") unless key?(:F) || key?(:Win)
71
+ unless key?(:Win) || key?(:Mac) || key?(:Unix) || key?(:F)
72
+ yield("Launch action key /F required if /Win, /Mac and /Unix are absent")
73
+ end
70
74
  end
71
75
 
72
76
  end
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2024 Thomas Leitner
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as