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
@@ -48,6 +48,8 @@ module HexaPDF
48
48
  # See: PDF2.0 s12.5.6.19, HexaPDF::Type::Annotation
49
49
  class Widget < Annotation
50
50
 
51
+ include BorderStyling
52
+
51
53
  # The dictionary used by the /MK key of the widget annotation.
52
54
  class AppearanceCharacteristics < Dictionary
53
55
 
@@ -122,111 +124,21 @@ module HexaPDF
122
124
  end
123
125
  end
124
126
 
125
- # Describes the border of an annotation.
126
- #
127
- # The +color+ property is either +nil+ if the border is transparent or else a device color
128
- # object - see HexaPDF::Content::ColorSpace.
129
- #
130
- # The +style+ property can be one of the following:
131
- #
132
- # :solid:: Solid line.
133
- # :beveled:: Embossed rectangle seemingly raised above the surface of the page.
134
- # :inset:: Engraved rectangle receeding into the page.
135
- # :underlined:: Underlined, i.e. only the bottom border is draw.
136
- # Array: Dash array describing how to dash the line.
137
- BorderStyle = Struct.new(:width, :color, :style, :horizontal_corner_radius,
138
- :vertical_corner_radius)
139
-
140
- # :call-seq:
141
- # widget.border_style => border_style
142
- # widget.border_style(color: 0, width: 1, style: :solid) => widget
143
- #
144
- # Returns a BorderStyle instance representing the border style of the widget when no
145
- # argument is given. Otherwise sets the border style of the widget and returns self.
146
- #
147
- # When setting a border style, arguments that are not provided will use the default: a
148
- # border with a solid, black, 1pt wide line. This also means that multiple invocations will
149
- # reset *all* prior values.
150
- #
151
- # +color+:: The color of the border. See
152
- # HexaPDF::Content::ColorSpace.device_color_from_specification for information on
153
- # the allowed arguments.
154
- #
155
- # If the special value +:transparent+ is used when setting the color, a
156
- # transparent is used. A transparent border will return a +nil+ value when getting
157
- # the border color.
158
- #
159
- # +width+:: The width of the border. If set to 0, no border is shown.
160
- #
161
- # +style+:: Defines how the border is drawn. can be one of the following:
162
- #
163
- # +:solid+:: Draws a solid border.
164
- # +:beveled+:: Draws a beveled border.
165
- # +:inset+:: Draws an inset border.
166
- # +:underlined+:: Draws only the bottom border.
167
- # Array:: An array specifying a line dash pattern (see
168
- # HexaPDF::Content::LineDashPattern)
169
- def border_style(color: nil, width: nil, style: nil)
170
- if color || width || style
171
- color = if color == :transparent
172
- []
173
- else
174
- Content::ColorSpace.device_color_from_specification(color || 0).components
175
- end
176
- width ||= 1
177
- style ||= :solid
178
-
179
- (self[:MK] ||= {})[:BC] = color
180
- bs = self[:BS] = {W: width}
181
- case style
182
- when :solid then bs[:S] = :S
183
- when :beveled then bs[:S] = :B
184
- when :inset then bs[:S] = :I
185
- when :underlined then bs[:S] = :U
186
- when Array
187
- bs[:S] = :D
188
- bs[:D] = style
189
- else
190
- raise ArgumentError, "Unknown value #{style} for style argument"
191
- end
192
- self
193
- else
194
- result = BorderStyle.new(1, nil, :solid, 0, 0)
195
- if (ac = self[:MK]) && (bc = ac[:BC]) && !bc.empty?
196
- result.color = Content::ColorSpace.prenormalized_device_color(bc.value)
197
- end
198
-
199
- if (bs = self[:BS])
200
- result.width = bs[:W] if bs.key?(:W)
201
- result.style = case bs[:S]
202
- when :S then :solid
203
- when :B then :beveled
204
- when :I then :inset
205
- when :U then :underlined
206
- when :D then bs[:D].value
207
- else :solid
208
- end
209
- elsif key?(:Border)
210
- border = self[:Border]
211
- result.horizontal_corner_radius = border[0]
212
- result.vertical_corner_radius = border[1]
213
- result.width = border[2]
214
- result.style = border[3] if border[3]
215
- end
216
-
217
- result
218
- end
219
- end
220
-
221
- # Describes the marker style of a check box or radio button widget.
127
+ # Describes the marker style of a check box, radio button or push button widget.
222
128
  class MarkerStyle
223
129
 
224
- # The kind of marker that is shown inside the widget. Can either be one of the symbols
225
- # +:check+, +:circle+, +:cross+, +:diamond+, +:square+ or +:star+, or a one character
226
- # string. The latter is interpreted using the ZapfDingbats font.
130
+ # The kind of marker that is shown inside the widget.
227
131
  #
228
- # If an empty string is set, it is treated as if +nil+ was set, i.e. it shows the default
229
- # marker for the field type.
132
+ # Radion buttons and check boxes::
133
+ # Can either be one of the symbols +:check+, +:circle+, +:cross+, +:diamond+,
134
+ # +:square+ or +:star+, or a one character string. The latter is interpreted using the
135
+ # ZapfDingbats font.
136
+ #
137
+ # If an empty string is set, it is treated as if +nil+ was set, i.e. it shows the
138
+ # default marker for the field type.
139
+ #
140
+ # Push buttons:
141
+ # The caption string.
230
142
  attr_reader :style
231
143
 
232
144
  # The size of the marker in PDF points that is shown inside the widget. The special value
@@ -237,41 +149,59 @@ module HexaPDF
237
149
  # HexaPDF::Content::ColorSpace.
238
150
  attr_reader :color
239
151
 
152
+ # The resource name of the font that should be used for the caption.
153
+ #
154
+ # This is only used for push button widgets.
155
+ attr_reader :font_name
156
+
240
157
  # Creates a new instance with the given values.
241
- def initialize(style, size, color)
158
+ def initialize(style, size, color, font_name)
242
159
  @style = style
243
160
  @size = size
244
161
  @color = color
162
+ @font_name = font_name
245
163
  end
246
164
 
247
165
  end
248
166
 
249
167
  # :call-seq:
250
- # widget.marker_style => marker_style
251
- # widget.marker_style(style: nil, size: nil, color: nil) => widget
168
+ # widget.marker_style => marker_style
169
+ # widget.marker_style(style: nil, size: nil, color: nil, font_name: nil) => widget
252
170
  #
253
171
  # Returns a MarkerStyle instance representing the marker style of the widget when no
254
172
  # argument is given. Otherwise sets the button marker style of the widget and returns self.
255
173
  #
256
- # This method returns valid information only for check boxes and radio buttons!
174
+ # This method returns valid information only for check boxes, radio buttons and push buttons!
257
175
  #
258
- # When setting a marker style, arguments that are not provided will use the default: a black
259
- # auto-sized checkmark (i.e. :check for for check boxes) or circle (:circle for radio
260
- # buttons). This also means that multiple invocations will reset *all* prior values.
176
+ # When setting a marker style, arguments that are not provided will use the default:
261
177
  #
262
- # Note: The marker is called "normal caption" in the PDF 1.7 spec and the /CA entry of the
178
+ # * For check boxes a black auto-sized checkmark (i.e. :check)
179
+ # * For radio buttons a black auto-sized circle (i.e. :circle)
180
+ # * For push buttons a black 9pt empty text using Helvetica
181
+ #
182
+ # This also means that multiple invocations will reset *all* prior values.
183
+ #
184
+ # Note that the +font_name+ argument must be a valid HexaPDF font name (this is in contrast
185
+ # to MarkerStyle#font_name which returns the resource name of the font).
186
+ #
187
+ # Note: The marker is called "normal caption" in the PDF 2.0 spec and the /CA entry of the
263
188
  # associated appearance characteristics dictionary. The marker size and color are set using
264
189
  # the /DA key on the widget (although /DA is not defined for widget, this is how Acrobat
265
190
  # does it).
266
191
  #
267
192
  # See: PDF2.0 s12.5.6.19 and s12.7.4.3
268
- def marker_style(style: nil, size: nil, color: nil)
193
+ def marker_style(style: nil, size: nil, color: nil, font_name: nil)
269
194
  field = form_field
270
- if style || size || color
271
- style ||= (field.check_box? ? :check : :cicrle)
272
- size ||= 0
195
+ if style || size || color || font_name
196
+ style ||= case field.concrete_field_type
197
+ when :check_box then :check
198
+ when :radio_button then :circle
199
+ when :push_button then ''
200
+ end
201
+ size ||= (field.push_button? ? 9 : 0)
273
202
  color = Content::ColorSpace.device_color_from_specification(color || 0)
274
203
  serialized_color = Content::ColorSpace.serialize_device_color(color)
204
+ font_name ||= 'Helvetica'
275
205
 
276
206
  self[:MK] ||= {}
277
207
  self[:MK][:CA] = case style
@@ -285,7 +215,13 @@ module HexaPDF
285
215
  else
286
216
  raise ArgumentError, "Unknown value #{style} for argument 'style'"
287
217
  end
288
- self[:DA] = "/ZaDb #{size} Tf #{serialized_color}".strip
218
+ self[:DA] = if field.push_button?
219
+ name = document.acro_form(create: true).default_resources.
220
+ add_font(document.fonts.add(font_name).pdf_object)
221
+ "/#{name} #{size} Tf #{serialized_color}".strip
222
+ else
223
+ "/ZaDb #{size} Tf #{serialized_color}".strip
224
+ end
289
225
  else
290
226
  style = case self[:MK]&.[](:CA)
291
227
  when '4' then :check
@@ -305,10 +241,12 @@ module HexaPDF
305
241
  size = 0
306
242
  color = HexaPDF::Content::ColorSpace.prenormalized_device_color([0])
307
243
  if (da = self[:DA] || field[:DA])
308
- _, size, color = HexaPDF::Type::AcroForm::VariableTextField.parse_appearance_string(da)
244
+ font_name, da_size, da_color = AcroForm::VariableTextField.parse_appearance_string(da)
245
+ size = da_size || size
246
+ color = da_color || color
309
247
  end
310
248
 
311
- MarkerStyle.new(style, size, color)
249
+ MarkerStyle.new(style, size, color, font_name)
312
250
  end
313
251
  end
314
252
 
@@ -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,18 @@ module HexaPDF
48
48
  autoload(:Text, 'hexapdf/type/annotations/text')
49
49
  autoload(:Link, 'hexapdf/type/annotations/link')
50
50
  autoload(:Widget, 'hexapdf/type/annotations/widget')
51
+ autoload(:BorderStyling, 'hexapdf/type/annotations/border_styling')
52
+ autoload(:Line, 'hexapdf/type/annotations/line')
53
+ autoload(:AppearanceGenerator, 'hexapdf/type/annotations/appearance_generator')
54
+ autoload(:BorderEffect, 'hexapdf/type/annotations/border_effect')
55
+ autoload(:InteriorColor, 'hexapdf/type/annotations/interior_color')
56
+ autoload(:SquareCircle, 'hexapdf/type/annotations/square_circle')
57
+ autoload(:Square, 'hexapdf/type/annotations/square')
58
+ autoload(:Circle, 'hexapdf/type/annotations/circle')
59
+ autoload(:LineEndingStyling, 'hexapdf/type/annotations/line_ending_styling')
60
+ autoload(:PolygonPolyline, 'hexapdf/type/annotations/polygon_polyline')
61
+ autoload(:Polygon, 'hexapdf/type/annotations/polygon')
62
+ autoload(:Polyline, 'hexapdf/type/annotations/polyline')
51
63
 
52
64
  end
53
65
 
@@ -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
@@ -72,7 +72,7 @@ module HexaPDF
72
72
  define_field :URI, type: Dictionary, version: '1.1'
73
73
  define_field :AcroForm, type: :XXAcroForm, version: '1.2'
74
74
  define_field :Metadata, type: :Metadata, indirect: true, version: '1.4'
75
- define_field :StructTreeRoot, type: Dictionary, version: '1.3'
75
+ define_field :StructTreeRoot, type: :StructTreeRoot, version: '1.3'
76
76
  define_field :MarkInfo, type: :XXMarkInformation, version: '1.4'
77
77
  define_field :Lang, type: String, version: '1.4'
78
78
  define_field :SpiderInfo, type: Dictionary, version: '1.3'
@@ -84,6 +84,9 @@ module HexaPDF
84
84
  define_field :Requirements, type: PDFArray, version: '1.7'
85
85
  define_field :Collection, type: Dictionary, version: '1.7'
86
86
  define_field :NeedsRendering, type: Boolean, version: '1.7'
87
+ define_field :DSS, type: Dictionary, version: '2.0'
88
+ define_field :AF, type: PDFArray, version: '2.0'
89
+ define_field :DPartRoot, type: Dictionary, version: '2.0'
87
90
 
88
91
  # Returns +true+ since catalog objects must always be indirect.
89
92
  def must_be_indirect?
@@ -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
@@ -61,13 +61,16 @@ module HexaPDF
61
61
 
62
62
  DEFAULT_WIDTH = 1000 # :nodoc:
63
63
 
64
+ define_field :Subtype, type: Symbol, required: true,
65
+ allowed_values: [:CIDFontType0, :CIDFontType2]
64
66
  define_field :BaseFont, type: Symbol, required: true
65
67
  define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
66
- define_field :FontDescriptor, type: :FontDescriptor, indirect: true, required: true
67
- define_field :DW, type: Integer, default: DEFAULT_WIDTH
68
+ define_field :FontDescriptor, type: :FontDescriptor, required: true
69
+ define_field :DW, type: Numeric, default: DEFAULT_WIDTH
68
70
  define_field :W, type: PDFArray
69
71
  define_field :DW2, type: PDFArray, default: [880, -1100]
70
72
  define_field :W2, type: PDFArray
73
+ define_field :CIDToGIDMap, type: [Stream, Symbol]
71
74
 
72
75
  # Returns the unscaled width of the given CID in glyph units, or 0 if the width for the CID is
73
76
  # missing.
@@ -0,0 +1,58 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2025 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/stream'
38
+
39
+ module HexaPDF
40
+ module Type
41
+
42
+ # Represents an embedded CMap file.
43
+ #
44
+ # See: PDF2.0 s9.7.5.3
45
+ class CMap < Stream
46
+
47
+ define_type :CMap
48
+
49
+ define_field :Type, type: Symbol, required: true, default: type
50
+ define_field :CMapName, type: Symbol, required: true
51
+ define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
52
+ define_field :WMode, type: Integer
53
+ define_field :UseCMap, type: [Stream, Symbol]
54
+
55
+ end
56
+
57
+ end
58
+ 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
@@ -78,19 +78,22 @@ module HexaPDF
78
78
 
79
79
  define_type :Filespec
80
80
 
81
- define_field :Type, type: Symbol, default: type, required: true
82
- define_field :FS, type: Symbol
83
- define_field :F, type: PDFByteString
84
- define_field :UF, type: String, version: '1.7'
85
- define_field :DOS, type: PDFByteString
86
- define_field :Mac, type: PDFByteString
87
- define_field :Unix, type: PDFByteString
88
- define_field :ID, type: PDFArray
89
- define_field :V, type: Boolean, version: '1.2'
90
- define_field :EF, type: :XXFilespecEFDictionary, version: '1.7'
91
- define_field :RF, type: Dictionary, version: '1.3'
92
- define_field :Desc, type: String, version: '1.6'
93
- define_field :CI, type: Dictionary, version: '1.7'
81
+ define_field :Type, type: Symbol, default: type, required: true
82
+ define_field :FS, type: Symbol
83
+ define_field :F, type: PDFByteString
84
+ define_field :UF, type: String, version: '1.7'
85
+ define_field :DOS, type: PDFByteString
86
+ define_field :Mac, type: PDFByteString
87
+ define_field :Unix, type: PDFByteString
88
+ define_field :ID, type: PDFArray
89
+ define_field :V, type: Boolean, version: '1.2'
90
+ define_field :EF, type: :XXFilespecEFDictionary, version: '1.7'
91
+ define_field :RF, type: Dictionary, version: '1.3'
92
+ define_field :Desc, type: String, version: '1.6'
93
+ define_field :CI, type: Dictionary, version: '1.7'
94
+ define_field :Thumb, type: Stream, version: '2.0'
95
+ define_field :EP, type: Dictionary, version: '2.0'
96
+ define_field :AF, type: Symbol, version: '2.0', default: :Unspecified
94
97
 
95
98
  # Returns +true+ if this file specification references an URL and not a file.
96
99
  def url?
@@ -114,7 +117,7 @@ module HexaPDF
114
117
 
115
118
  # Sets the file specification string to the given filename.
116
119
  #
117
- # Since the /Unix, /Mac and /DOS fields are obsolescent, only the /F and /UF fields are set.
120
+ # Since the /Unix, /Mac and /DOS fields are deprecated, only the /F and /UF fields are set.
118
121
  def path=(filename)
119
122
  self[:UF] = filename
120
123
  self[:F] = filename.b
@@ -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
@@ -57,7 +57,7 @@ module HexaPDF
57
57
  define_field :FontStretch, type: Symbol, version: '1.5',
58
58
  allowed_values: [:UltraCondensed, :ExtraCondensed, :Condensed, :SemiCondensed,
59
59
  :Normal, :SemiExpanded, :Expanded, :ExtraExpanded, :UltraExpanded]
60
- define_field :FontWeight, type: Numeric, version: '1.5'
60
+ define_field :FontWeight, type: Integer, version: '1.5' # also see validation
61
61
  define_field :Flags, type: Integer, required: true
62
62
  define_field :FontBBox, type: Rectangle
63
63
  define_field :ItalicAngle, type: Numeric, required: true
@@ -76,6 +76,7 @@ module HexaPDF
76
76
  define_field :FontFile3, type: Stream, version: '1.2'
77
77
  define_field :CharSet, type: [PDFByteString, String], version: '1.1'
78
78
 
79
+ # From PDF2.0 s9.8.3.1
79
80
  define_field :Style, type: Dictionary
80
81
  define_field :Lang, type: Symbol, version: '1.5'
81
82
  define_field :FD, type: Dictionary
@@ -98,13 +99,13 @@ module HexaPDF
98
99
 
99
100
  font_weight = self[:FontWeight]
100
101
  if font_weight && !ALLOWED_FONT_WEIGHTS.include?(font_weight)
101
- yield("Field FontWeight does not contain an allowed value", true)
102
+ yield("Field FontWeight contains the disallowed value #{font_weight}", true)
102
103
  delete(:FontWeight)
103
104
  end
104
105
 
105
106
  descent = self[:Descent]
106
107
  if descent && descent > 0
107
- yield("The /Descent value needs to be a negative number", true)
108
+ yield("The /Descent value needs to be zero or negative", true)
108
109
  self[:Descent] = -descent
109
110
  end
110
111
  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
@@ -47,10 +47,12 @@ module HexaPDF
47
47
  # See: PDF2.0 s9.6
48
48
  class FontSimple < Font
49
49
 
50
+ # Only the common fields are defined here, the rest in FontType1, FontType3, FontTrueType
51
+ define_field :Name, type: Symbol
50
52
  define_field :FirstChar, type: Integer
51
53
  define_field :LastChar, type: Integer
52
54
  define_field :Widths, type: PDFArray
53
- define_field :FontDescriptor, type: :FontDescriptor, indirect: true
55
+ define_field :FontDescriptor, type: :FontDescriptor
54
56
  define_field :Encoding, type: [Dictionary, Symbol]
55
57
 
56
58
  # Returns the font descriptor. May be +nil+ for a standard 14 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
@@ -41,6 +41,8 @@ module HexaPDF
41
41
  module Type
42
42
 
43
43
  # Represents a TrueType font.
44
+ #
45
+ # See: PDF2.0 s9.6.3
44
46
  class FontTrueType < FontSimple
45
47
 
46
48
  define_field :Subtype, type: Symbol, required: true, default: :TrueType
@@ -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,7 +48,7 @@ module HexaPDF
48
48
  # Composite fonts also allow for vertical writing mode and support TrueType as well as OpenType
49
49
  # fonts.
50
50
  #
51
- # See: PDF2.0 s9.7
51
+ # See: PDF2.0 s9.7, s9.7.6.1
52
52
  class FontType0 < Font
53
53
 
54
54
  define_field :Subtype, type: Symbol, required: true, default: :Type0
@@ -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
@@ -170,6 +170,8 @@ module HexaPDF
170
170
  end
171
171
  end
172
172
 
173
+ PREDEFINED_ENCODING = [:MacRomanEncoding, :MacExpertEncoding, :WinAnsiEncoding] #:nodoc:
174
+
173
175
  # Validates the Type1 font dictionary.
174
176
  def perform_validation
175
177
  std_font = StandardFonts.standard_font?(self[:BaseFont])
@@ -178,6 +180,22 @@ module HexaPDF
178
180
  if !std_font && self[:FontDescriptor].nil?
179
181
  yield("Required field FontDescriptor is not set", false)
180
182
  end
183
+
184
+ encoding = self[:Encoding]
185
+ if encoding.kind_of?(Symbol) && !PREDEFINED_ENCODING.include?(encoding)
186
+ correctable = (self[:BaseFont] == :Symbol && encoding == :SymbolEncoding) ||
187
+ (!symbolic? && encoding == :StandardEncoding)
188
+ yield("The /Encoding value '#{encoding}' is invalid", correctable)
189
+ if correctable
190
+ if encoding == :SymbolEncoding
191
+ delete(:Encoding)
192
+ else
193
+ diffs = HexaPDF::Font::Encoding.for_name(:StandardEncoding).
194
+ to_compact_array(base_encoding: HexaPDF::Font::Encoding.for_name(:WinAnsiEncoding))
195
+ self[:Encoding] = {BaseEncoding: :WinAnsiEncoding, Differences: diffs}
196
+ end
197
+ end
198
+ end
181
199
  end
182
200
 
183
201
  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
@@ -49,7 +49,6 @@ module HexaPDF
49
49
  class FontType3 < FontSimple
50
50
 
51
51
  define_field :Subtype, type: Symbol, required: true, default: :Type3
52
- define_field :Name, type: Symbol
53
52
  define_field :FontBBox, type: Rectangle, required: true
54
53
  define_field :FontMatrix, type: PDFArray, required: true
55
54
  define_field :CharProcs, type: Dictionary, required: true