pdfrb 0.2.1 → 0.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 (406) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +24 -0
  4. data/Gemfile +1 -0
  5. data/PROPOSAL.canvas-clip.md +92 -0
  6. data/PROPOSAL.canvas-draw-image-matrix.md +87 -0
  7. data/PROPOSAL.canvas-rich-text.md +103 -0
  8. data/PROPOSAL.canvas-text-lines.md +77 -0
  9. data/PROPOSAL.canvas-transparency.md +106 -0
  10. data/PROPOSAL.external-font-metrics.md +129 -0
  11. data/PROPOSAL.font-embedding-fontfile2.md +88 -0
  12. data/PROPOSAL.font-resolver-ttc.md +105 -0
  13. data/PROPOSAL.font-resolver.md +96 -0
  14. data/PROPOSAL.font-subsetting.md +98 -0
  15. data/PROPOSAL.gradient-shadings.md +110 -0
  16. data/PROPOSAL.page-mediabox-setter.md +66 -0
  17. data/PROPOSAL.per-glyph-width.md +91 -0
  18. data/PROPOSAL.stringio-require.md +53 -0
  19. data/PROPOSAL.struct-tree-root.md +102 -0
  20. data/PROPOSAL.text-measurement.md +93 -0
  21. data/PROPOSAL.ttf-table-parsing-fix.md +112 -0
  22. data/RELEASE.md +48 -0
  23. data/lib/pdfrb/action/base.rb +21 -0
  24. data/lib/pdfrb/action/types.rb +178 -0
  25. data/lib/pdfrb/action.rb +55 -0
  26. data/lib/pdfrb/annotation/base.rb +79 -0
  27. data/lib/pdfrb/annotation/types.rb +222 -0
  28. data/lib/pdfrb/annotation.rb +78 -0
  29. data/lib/pdfrb/appearance/generator.rb +216 -0
  30. data/lib/pdfrb/appearance.rb +11 -0
  31. data/lib/pdfrb/arlington/object_definition.rb +2 -2
  32. data/lib/pdfrb/arlington/predicate/evaluator.rb +1 -1
  33. data/lib/pdfrb/arlington/predicate/functions.rb +25 -9
  34. data/lib/pdfrb/arlington/predicate.rb +1 -5
  35. data/lib/pdfrb/cli/batch.rb +18 -0
  36. data/lib/pdfrb/cli/debug_info.rb +18 -0
  37. data/lib/pdfrb/cli/files.rb +16 -0
  38. data/lib/pdfrb/cli/fonts.rb +16 -0
  39. data/lib/pdfrb/cli/form.rb +18 -0
  40. data/lib/pdfrb/cli/image2pdf.rb +18 -0
  41. data/lib/pdfrb/cli/images.rb +34 -0
  42. data/lib/pdfrb/cli/info.rb +20 -0
  43. data/lib/pdfrb/cli/inspect.rb +18 -0
  44. data/lib/pdfrb/cli/merge.rb +18 -0
  45. data/lib/pdfrb/cli/modify.rb +18 -0
  46. data/lib/pdfrb/cli/optimize.rb +18 -0
  47. data/lib/pdfrb/cli/split.rb +21 -0
  48. data/lib/pdfrb/cli/watermark.rb +18 -0
  49. data/lib/pdfrb/cli.rb +312 -7
  50. data/lib/pdfrb/color/color_space.rb +259 -0
  51. data/lib/pdfrb/color/icc_profile.rb +90 -0
  52. data/lib/pdfrb/color.rb +12 -0
  53. data/lib/pdfrb/compare/comparator.rb +244 -0
  54. data/lib/pdfrb/compare/report.rb +78 -0
  55. data/lib/pdfrb/compare.rb +42 -0
  56. data/lib/pdfrb/composer.rb +161 -0
  57. data/lib/pdfrb/conformance/pdf_a.rb +317 -56
  58. data/lib/pdfrb/conformance/pdf_ua.rb +186 -29
  59. data/lib/pdfrb/conformance/pdf_x.rb +247 -0
  60. data/lib/pdfrb/conformance/rule.rb +78 -0
  61. data/lib/pdfrb/conformance/structure_elements.rb +174 -0
  62. data/lib/pdfrb/conformance/verapdf_bridge.rb +92 -0
  63. data/lib/pdfrb/conformance.rb +7 -3
  64. data/lib/pdfrb/content/canvas.rb +217 -72
  65. data/lib/pdfrb/content/color_space.rb +157 -0
  66. data/lib/pdfrb/content/hidden_text_detector.rb +167 -0
  67. data/lib/pdfrb/content/operator.rb +21 -1
  68. data/lib/pdfrb/content/operators/clipping.rb +36 -0
  69. data/lib/pdfrb/content/operators/graphics_state_params.rb +15 -0
  70. data/lib/pdfrb/content/operators.rb +21 -0
  71. data/lib/pdfrb/content/shading/base.rb +139 -0
  72. data/lib/pdfrb/content/shading.rb +17 -0
  73. data/lib/pdfrb/content/smart_text_extractor.rb +85 -0
  74. data/lib/pdfrb/content/tiling_pattern.rb +78 -0
  75. data/lib/pdfrb/content/transformation_matrix.rb +61 -0
  76. data/lib/pdfrb/content.rb +7 -26
  77. data/lib/pdfrb/destination/fit.rb +185 -0
  78. data/lib/pdfrb/destination.rb +13 -0
  79. data/lib/pdfrb/digital_signature/cms_handler.rb +22 -0
  80. data/lib/pdfrb/digital_signature/signing.rb +107 -11
  81. data/lib/pdfrb/digital_signature/timestamp_handler.rb +45 -0
  82. data/lib/pdfrb/digital_signature/verification.rb +88 -9
  83. data/lib/pdfrb/digital_signature/verification_result.rb +14 -0
  84. data/lib/pdfrb/digital_signature.rb +26 -2
  85. data/lib/pdfrb/document/annotations.rb +120 -3
  86. data/lib/pdfrb/document/associated_files.rb +104 -0
  87. data/lib/pdfrb/document/colors.rb +95 -0
  88. data/lib/pdfrb/document/destinations.rb +127 -5
  89. data/lib/pdfrb/document/display.rb +84 -0
  90. data/lib/pdfrb/document/fonts.rb +417 -45
  91. data/lib/pdfrb/document/form.rb +338 -0
  92. data/lib/pdfrb/document/form_xobject.rb +68 -0
  93. data/lib/pdfrb/document/graphics_state.rb +91 -0
  94. data/lib/pdfrb/document/images.rb +4 -4
  95. data/lib/pdfrb/document/info.rb +102 -0
  96. data/lib/pdfrb/document/layers.rb +62 -0
  97. data/lib/pdfrb/document/metadata.rb +12 -5
  98. data/lib/pdfrb/document/output_intents.rb +91 -0
  99. data/lib/pdfrb/document/page_labels.rb +80 -0
  100. data/lib/pdfrb/document/pages.rb +68 -19
  101. data/lib/pdfrb/document/portfolio.rb +119 -0
  102. data/lib/pdfrb/document/shadings.rb +159 -0
  103. data/lib/pdfrb/document/stamps.rb +68 -0
  104. data/lib/pdfrb/document/structure.rb +242 -0
  105. data/lib/pdfrb/document.rb +73 -4
  106. data/lib/pdfrb/encryption/identity.rb +13 -0
  107. data/lib/pdfrb/encryption/password_verification.rb +53 -8
  108. data/lib/pdfrb/encryption/security_handler.rb +8 -5
  109. data/lib/pdfrb/encryption/standard_security_handler.rb +154 -81
  110. data/lib/pdfrb/encryption.rb +17 -0
  111. data/lib/pdfrb/error.rb +2 -2
  112. data/lib/pdfrb/filter/brotli_decode.rb +32 -0
  113. data/lib/pdfrb/filter/ccitt_fax_decode.rb +12 -0
  114. data/lib/pdfrb/filter/crypt.rb +2 -2
  115. data/lib/pdfrb/filter/dct_decode.rb +18 -0
  116. data/lib/pdfrb/filter/flate_decode.rb +4 -18
  117. data/lib/pdfrb/filter/jbig2_decode.rb +12 -0
  118. data/lib/pdfrb/filter/jpx_decode.rb +18 -0
  119. data/lib/pdfrb/filter/lzw_decode.rb +3 -2
  120. data/lib/pdfrb/filter/png_predictor.rb +94 -0
  121. data/lib/pdfrb/filter.rb +26 -13
  122. data/lib/pdfrb/font/afm_parser.rb +50 -26
  123. data/lib/pdfrb/font/cmap/writer.rb +9 -0
  124. data/lib/pdfrb/font/encoding/win_ansi_encoding.rb +17 -0
  125. data/lib/pdfrb/font/encoding.rb +32 -3
  126. data/lib/pdfrb/font/metrics_helper.rb +121 -0
  127. data/lib/pdfrb/font/true_type/file.rb +10 -1
  128. data/lib/pdfrb/font/true_type/glyf.rb +82 -0
  129. data/lib/pdfrb/font/true_type/kern.rb +58 -0
  130. data/lib/pdfrb/font/true_type/loca.rb +42 -0
  131. data/lib/pdfrb/font/true_type/maxp.rb +44 -0
  132. data/lib/pdfrb/font/true_type/name.rb +53 -0
  133. data/lib/pdfrb/font/true_type/post.rb +93 -0
  134. data/lib/pdfrb/font/true_type/subsetter.rb +3 -5
  135. data/lib/pdfrb/font/true_type/wrapper.rb +102 -0
  136. data/lib/pdfrb/font/true_type.rb +7 -0
  137. data/lib/pdfrb/font.rb +2 -0
  138. data/lib/pdfrb/font_loader/from_configuration.rb +19 -0
  139. data/lib/pdfrb/font_loader/from_file.rb +20 -0
  140. data/lib/pdfrb/font_loader/standard14.rb +20 -0
  141. data/lib/pdfrb/font_loader/variant_from_name.rb +36 -0
  142. data/lib/pdfrb/font_loader.rb +4 -0
  143. data/lib/pdfrb/font_resolver.rb +138 -0
  144. data/lib/pdfrb/image/audit.rb +94 -0
  145. data/lib/pdfrb/image/downsampler.rb +124 -0
  146. data/lib/pdfrb/image.rb +13 -0
  147. data/lib/pdfrb/image_loader/jpeg.rb +39 -58
  148. data/lib/pdfrb/image_loader/png.rb +31 -257
  149. data/lib/pdfrb/layout/bidi.rb +198 -0
  150. data/lib/pdfrb/layout/box.rb +49 -0
  151. data/lib/pdfrb/layout/box_fitter.rb +54 -0
  152. data/lib/pdfrb/layout/column_box.rb +71 -0
  153. data/lib/pdfrb/layout/container_box.rb +45 -0
  154. data/lib/pdfrb/layout/frame.rb +67 -0
  155. data/lib/pdfrb/layout/image_box.rb +44 -0
  156. data/lib/pdfrb/layout/inline_box.rb +25 -0
  157. data/lib/pdfrb/layout/line.rb +55 -0
  158. data/lib/pdfrb/layout/list_box.rb +87 -0
  159. data/lib/pdfrb/layout/numeric_refinements.rb +43 -0
  160. data/lib/pdfrb/layout/page_style.rb +65 -0
  161. data/lib/pdfrb/layout/style.rb +62 -0
  162. data/lib/pdfrb/layout/table_box.rb +66 -0
  163. data/lib/pdfrb/layout/text_box.rb +38 -0
  164. data/lib/pdfrb/layout/text_fragment.rb +45 -0
  165. data/lib/pdfrb/layout/text_layouter.rb +123 -0
  166. data/lib/pdfrb/layout.rb +28 -0
  167. data/lib/pdfrb/linearization/hint_stream.rb +93 -0
  168. data/lib/pdfrb/linearization/writer.rb +259 -0
  169. data/lib/pdfrb/linearization.rb +21 -0
  170. data/lib/pdfrb/model/cos/dictionary.rb +12 -0
  171. data/lib/pdfrb/model/pdf_array.rb +2 -2
  172. data/lib/pdfrb/model/type/action.rb +42 -0
  173. data/lib/pdfrb/model/type/action_go_to_3d_view.rb +14 -0
  174. data/lib/pdfrb/model/type/action_go_to_dp.rb +16 -0
  175. data/lib/pdfrb/model/type/action_go_to_r.rb +26 -0
  176. data/lib/pdfrb/model/type/action_goto.rb +34 -0
  177. data/lib/pdfrb/model/type/action_hide.rb +26 -0
  178. data/lib/pdfrb/model/type/action_import_data.rb +18 -0
  179. data/lib/pdfrb/model/type/action_java_script.rb +18 -0
  180. data/lib/pdfrb/model/type/action_launch.rb +22 -0
  181. data/lib/pdfrb/model/type/action_movie.rb +22 -0
  182. data/lib/pdfrb/model/type/action_named.rb +23 -0
  183. data/lib/pdfrb/model/type/action_nop.rb +12 -0
  184. data/lib/pdfrb/model/type/action_rendition.rb +28 -0
  185. data/lib/pdfrb/model/type/action_reset_form.rb +22 -0
  186. data/lib/pdfrb/model/type/action_rich_media_execute.rb +17 -0
  187. data/lib/pdfrb/model/type/action_set_ocg_state.rb +32 -0
  188. data/lib/pdfrb/model/type/action_set_state.rb +14 -0
  189. data/lib/pdfrb/model/type/action_sound_action.rb +23 -0
  190. data/lib/pdfrb/model/type/action_submit_form.rb +64 -0
  191. data/lib/pdfrb/model/type/action_thread.rb +23 -0
  192. data/lib/pdfrb/model/type/action_trans.rb +30 -0
  193. data/lib/pdfrb/model/type/action_uri.rb +30 -0
  194. data/lib/pdfrb/model/type/af_embedded_file.rb +11 -0
  195. data/lib/pdfrb/model/type/af_file_specification.rb +34 -0
  196. data/lib/pdfrb/model/type/annotation.rb +49 -10
  197. data/lib/pdfrb/model/type/appearance.rb +41 -0
  198. data/lib/pdfrb/model/type/appearance_characteristics.rb +36 -0
  199. data/lib/pdfrb/model/type/appearance_generator.rb +22 -0
  200. data/lib/pdfrb/model/type/appearance_trap_net.rb +84 -0
  201. data/lib/pdfrb/model/type/border_effect.rb +25 -0
  202. data/lib/pdfrb/model/type/border_styling.rb +38 -0
  203. data/lib/pdfrb/model/type/box_color_info.rb +21 -0
  204. data/lib/pdfrb/model/type/box_style.rb +19 -0
  205. data/lib/pdfrb/model/type/button.rb +17 -0
  206. data/lib/pdfrb/model/type/cal_gray.rb +17 -0
  207. data/lib/pdfrb/model/type/cal_rgb.rb +22 -0
  208. data/lib/pdfrb/model/type/caret_annotation.rb +21 -0
  209. data/lib/pdfrb/model/type/catalog.rb +99 -16
  210. data/lib/pdfrb/model/type/choice.rb +21 -0
  211. data/lib/pdfrb/model/type/cid_font.rb +52 -1
  212. data/lib/pdfrb/model/type/cid_font_descriptor_metrics.rb +28 -0
  213. data/lib/pdfrb/model/type/cid_system_info.rb +28 -0
  214. data/lib/pdfrb/model/type/circle_annotation.rb +20 -0
  215. data/lib/pdfrb/model/type/collection.rb +27 -0
  216. data/lib/pdfrb/model/type/collection_field.rb +24 -0
  217. data/lib/pdfrb/model/type/collection_item.rb +19 -0
  218. data/lib/pdfrb/model/type/collection_schema.rb +25 -0
  219. data/lib/pdfrb/model/type/collection_sort.rb +13 -0
  220. data/lib/pdfrb/model/type/crypt_filter.rb +58 -0
  221. data/lib/pdfrb/model/type/device_n.rb +37 -0
  222. data/lib/pdfrb/model/type/device_n_mixing_hints.rb +17 -0
  223. data/lib/pdfrb/model/type/device_n_process.rb +13 -0
  224. data/lib/pdfrb/model/type/doc_mdp_transform_parameters.rb +21 -0
  225. data/lib/pdfrb/model/type/document_security_store.rb +55 -0
  226. data/lib/pdfrb/model/type/embedded_file.rb +19 -0
  227. data/lib/pdfrb/model/type/embedded_file_parameter.rb +48 -0
  228. data/lib/pdfrb/model/type/encryption_public_key.rb +38 -0
  229. data/lib/pdfrb/model/type/encryption_standard.rb +68 -0
  230. data/lib/pdfrb/model/type/field_mdp_transform_parameters.rb +26 -0
  231. data/lib/pdfrb/model/type/file_attachment_annotation.rb +29 -0
  232. data/lib/pdfrb/model/type/file_spec_ef.rb +22 -0
  233. data/lib/pdfrb/model/type/file_spec_rf.rb +21 -0
  234. data/lib/pdfrb/model/type/file_specification.rb +43 -0
  235. data/lib/pdfrb/model/type/file_trailer.rb +54 -0
  236. data/lib/pdfrb/model/type/font.rb +73 -2
  237. data/lib/pdfrb/model/type/font_cid_type0.rb +17 -0
  238. data/lib/pdfrb/model/type/font_cid_type2.rb +17 -0
  239. data/lib/pdfrb/model/type/font_descriptor.rb +47 -0
  240. data/lib/pdfrb/model/type/font_descriptor_cid_type0.rb +15 -0
  241. data/lib/pdfrb/model/type/font_descriptor_cid_type2.rb +15 -0
  242. data/lib/pdfrb/model/type/font_encoding.rb +47 -0
  243. data/lib/pdfrb/model/type/font_file.rb +28 -0
  244. data/lib/pdfrb/model/type/font_file2.rb +32 -0
  245. data/lib/pdfrb/model/type/font_file3.rb +23 -0
  246. data/lib/pdfrb/model/type/font_multiple_master.rb +60 -0
  247. data/lib/pdfrb/model/type/font_true_type.rb +1 -1
  248. data/lib/pdfrb/model/type/font_type0.rb +1 -1
  249. data/lib/pdfrb/model/type/font_type1.rb +1 -1
  250. data/lib/pdfrb/model/type/font_type3.rb +1 -1
  251. data/lib/pdfrb/model/type/form_field.rb +73 -0
  252. data/lib/pdfrb/model/type/free_text_annotation.rb +37 -0
  253. data/lib/pdfrb/model/type/function.rb +42 -0
  254. data/lib/pdfrb/model/type/function_exponential.rb +31 -0
  255. data/lib/pdfrb/model/type/function_postscript.rb +25 -0
  256. data/lib/pdfrb/model/type/function_sampled.rb +55 -0
  257. data/lib/pdfrb/model/type/function_stitching.rb +33 -0
  258. data/lib/pdfrb/model/type/generic_appearance.rb +40 -0
  259. data/lib/pdfrb/model/type/graphics_state_parameter.rb +69 -0
  260. data/lib/pdfrb/model/type/halftone.rb +21 -0
  261. data/lib/pdfrb/model/type/halftone_type1.rb +17 -0
  262. data/lib/pdfrb/model/type/halftone_type10.rb +16 -0
  263. data/lib/pdfrb/model/type/halftone_type16.rb +11 -0
  264. data/lib/pdfrb/model/type/halftone_type5.rb +24 -0
  265. data/lib/pdfrb/model/type/halftone_type6.rb +16 -0
  266. data/lib/pdfrb/model/type/highlight_annotation.rb +11 -0
  267. data/lib/pdfrb/model/type/icc_based_color_space.rb +24 -0
  268. data/lib/pdfrb/model/type/icon_fit.rb +31 -0
  269. data/lib/pdfrb/model/type/indexed.rb +32 -0
  270. data/lib/pdfrb/model/type/info.rb +44 -0
  271. data/lib/pdfrb/model/type/ink_annotation.rb +29 -0
  272. data/lib/pdfrb/model/type/interactive_form.rb +36 -0
  273. data/lib/pdfrb/model/type/interior_color.rb +12 -0
  274. data/lib/pdfrb/model/type/jbig2_globals.rb +15 -0
  275. data/lib/pdfrb/model/type/lab.rb +27 -0
  276. data/lib/pdfrb/model/type/line_annotation.rb +44 -0
  277. data/lib/pdfrb/model/type/line_ending_styling.rb +39 -0
  278. data/lib/pdfrb/model/type/link_annotation.rb +41 -0
  279. data/lib/pdfrb/model/type/link_appearance.rb +9 -0
  280. data/lib/pdfrb/model/type/mark_information.rb +23 -0
  281. data/lib/pdfrb/model/type/marked_content_reference.rb +24 -0
  282. data/lib/pdfrb/model/type/markup_annotation.rb +36 -0
  283. data/lib/pdfrb/model/type/mdp_dict.rb +28 -0
  284. data/lib/pdfrb/model/type/measure.rb +39 -0
  285. data/lib/pdfrb/model/type/media_clip.rb +28 -0
  286. data/lib/pdfrb/model/type/media_offset.rb +106 -0
  287. data/lib/pdfrb/model/type/metadata.rb +27 -3
  288. data/lib/pdfrb/model/type/misc_helpers.rb +75 -0
  289. data/lib/pdfrb/model/type/movie.rb +28 -0
  290. data/lib/pdfrb/model/type/names.rb +51 -0
  291. data/lib/pdfrb/model/type/namespace.rb +27 -0
  292. data/lib/pdfrb/model/type/object_reference.rb +31 -0
  293. data/lib/pdfrb/model/type/object_stream.rb +38 -0
  294. data/lib/pdfrb/model/type/opt_content_ext.rb +94 -0
  295. data/lib/pdfrb/model/type/opt_content_page_element.rb +18 -0
  296. data/lib/pdfrb/model/type/optional_content_config.rb +56 -0
  297. data/lib/pdfrb/model/type/optional_content_group.rb +35 -10
  298. data/lib/pdfrb/model/type/optional_content_membership.rb +36 -2
  299. data/lib/pdfrb/model/type/optional_content_properties.rb +16 -1
  300. data/lib/pdfrb/model/type/outline.rb +40 -6
  301. data/lib/pdfrb/model/type/outline_item.rb +45 -0
  302. data/lib/pdfrb/model/type/output_intent.rb +30 -0
  303. data/lib/pdfrb/model/type/page.rb +127 -0
  304. data/lib/pdfrb/model/type/page_label.rb +68 -0
  305. data/lib/pdfrb/model/type/page_tree_node.rb +51 -16
  306. data/lib/pdfrb/model/type/page_tree_node_root.rb +15 -0
  307. data/lib/pdfrb/model/type/pattern.rb +16 -0
  308. data/lib/pdfrb/model/type/pattern_shading.rb +25 -0
  309. data/lib/pdfrb/model/type/pattern_tiling.rb +25 -0
  310. data/lib/pdfrb/model/type/polygon_annotation.rb +29 -0
  311. data/lib/pdfrb/model/type/polygon_polyline.rb +14 -0
  312. data/lib/pdfrb/model/type/polyline_annotation.rb +29 -0
  313. data/lib/pdfrb/model/type/popup_annotation.rb +20 -0
  314. data/lib/pdfrb/model/type/printer_mark_annotation.rb +13 -0
  315. data/lib/pdfrb/model/type/redact_annotation.rb +28 -0
  316. data/lib/pdfrb/model/type/rendition.rb +31 -0
  317. data/lib/pdfrb/model/type/resources.rb +59 -14
  318. data/lib/pdfrb/model/type/rich_media_activation.rb +24 -0
  319. data/lib/pdfrb/model/type/rich_media_animation.rb +25 -0
  320. data/lib/pdfrb/model/type/rich_media_annotation.rb +18 -0
  321. data/lib/pdfrb/model/type/rich_media_command.rb +19 -0
  322. data/lib/pdfrb/model/type/rich_media_configuration.rb +32 -0
  323. data/lib/pdfrb/model/type/rich_media_content.rb +28 -0
  324. data/lib/pdfrb/model/type/rich_media_cue_point.rb +18 -0
  325. data/lib/pdfrb/model/type/rich_media_deactivation.rb +17 -0
  326. data/lib/pdfrb/model/type/rich_media_instance.rb +33 -0
  327. data/lib/pdfrb/model/type/rich_media_presentation.rb +29 -0
  328. data/lib/pdfrb/model/type/rich_media_settings.rb +33 -0
  329. data/lib/pdfrb/model/type/rich_media_window.rb +20 -0
  330. data/lib/pdfrb/model/type/screen_annotation.rb +19 -0
  331. data/lib/pdfrb/model/type/separation.rb +25 -0
  332. data/lib/pdfrb/model/type/sig_field_lock.rb +25 -0
  333. data/lib/pdfrb/model/type/sig_field_seed_value.rb +25 -0
  334. data/lib/pdfrb/model/type/signature.rb +65 -0
  335. data/lib/pdfrb/model/type/signature_build.rb +86 -0
  336. data/lib/pdfrb/model/type/signature_field.rb +17 -0
  337. data/lib/pdfrb/model/type/software_identifier.rb +19 -0
  338. data/lib/pdfrb/model/type/sound.rb +38 -0
  339. data/lib/pdfrb/model/type/sound_annotation.rb +21 -0
  340. data/lib/pdfrb/model/type/square_annotation.rb +24 -0
  341. data/lib/pdfrb/model/type/square_circle.rb +13 -0
  342. data/lib/pdfrb/model/type/squiggly_annotation.rb +11 -0
  343. data/lib/pdfrb/model/type/stamp_annotation.rb +19 -0
  344. data/lib/pdfrb/model/type/strikeout_annotation.rb +11 -0
  345. data/lib/pdfrb/model/type/struct_elem.rb +75 -0
  346. data/lib/pdfrb/model/type/struct_tree_root.rb +34 -0
  347. data/lib/pdfrb/model/type/structure_attributes.rb +44 -0
  348. data/lib/pdfrb/model/type/structure_element_kid.rb +33 -0
  349. data/lib/pdfrb/model/type/text_annotation.rb +25 -0
  350. data/lib/pdfrb/model/type/text_appearance.rb +9 -0
  351. data/lib/pdfrb/model/type/text_field.rb +21 -0
  352. data/lib/pdfrb/model/type/text_markup_annotation.rb +30 -0
  353. data/lib/pdfrb/model/type/three_d_activation.rb +32 -0
  354. data/lib/pdfrb/model/type/three_d_animation_style.rb +24 -0
  355. data/lib/pdfrb/model/type/three_d_background.rb +28 -0
  356. data/lib/pdfrb/model/type/three_d_cross_section.rb +25 -0
  357. data/lib/pdfrb/model/type/three_d_lighting_scheme.rb +26 -0
  358. data/lib/pdfrb/model/type/three_d_measure.rb +20 -0
  359. data/lib/pdfrb/model/type/three_d_measure_3dc.rb +23 -0
  360. data/lib/pdfrb/model/type/three_d_measure_ad3.rb +14 -0
  361. data/lib/pdfrb/model/type/three_d_measure_ld3.rb +14 -0
  362. data/lib/pdfrb/model/type/three_d_measure_pd3.rb +20 -0
  363. data/lib/pdfrb/model/type/three_d_measure_rd3.rb +14 -0
  364. data/lib/pdfrb/model/type/three_d_node.rb +37 -0
  365. data/lib/pdfrb/model/type/three_d_reference.rb +21 -0
  366. data/lib/pdfrb/model/type/three_d_render_mode.rb +34 -0
  367. data/lib/pdfrb/model/type/three_d_stream.rb +48 -0
  368. data/lib/pdfrb/model/type/three_d_units.rb +18 -0
  369. data/lib/pdfrb/model/type/three_d_view.rb +40 -0
  370. data/lib/pdfrb/model/type/to_unicode_cmap_stream.rb +23 -0
  371. data/lib/pdfrb/model/type/transition.rb +68 -0
  372. data/lib/pdfrb/model/type/underline_annotation.rb +11 -0
  373. data/lib/pdfrb/model/type/ur_transform_parameters.rb +33 -0
  374. data/lib/pdfrb/model/type/uri_dict.rb +18 -0
  375. data/lib/pdfrb/model/type/url_alias.rb +19 -0
  376. data/lib/pdfrb/model/type/variable_text_field.rb +47 -0
  377. data/lib/pdfrb/model/type/viewer_preferences.rb +42 -0
  378. data/lib/pdfrb/model/type/watermark_annotation.rb +13 -0
  379. data/lib/pdfrb/model/type/widget_annotation.rb +48 -0
  380. data/lib/pdfrb/model/type/widget_appearance.rb +9 -0
  381. data/lib/pdfrb/model/type/xobject_form.rb +41 -0
  382. data/lib/pdfrb/model/type/xobject_image.rb +56 -0
  383. data/lib/pdfrb/model/type/xref_stream.rb +37 -0
  384. data/lib/pdfrb/model/type.rb +286 -6
  385. data/lib/pdfrb/serializer.rb +2 -2
  386. data/lib/pdfrb/source/tokenizer.rb +0 -2
  387. data/lib/pdfrb/task/benchmark.rb +83 -0
  388. data/lib/pdfrb/task/extract_text.rb +1 -1
  389. data/lib/pdfrb/task/generate_corpus.rb +130 -0
  390. data/lib/pdfrb/task/memory_profile.rb +84 -0
  391. data/lib/pdfrb/task/optimize.rb +97 -7
  392. data/lib/pdfrb/task.rb +3 -3
  393. data/lib/pdfrb/test_utils.rb +112 -0
  394. data/lib/pdfrb/validator.rb +82 -0
  395. data/lib/pdfrb/version.rb +1 -1
  396. data/lib/pdfrb/writer.rb +117 -27
  397. data/lib/pdfrb/xmp/packet.rb +122 -0
  398. data/lib/pdfrb/xmp/schemas.rb +96 -0
  399. data/lib/pdfrb/xmp.rb +44 -0
  400. data/lib/pdfrb/xref_section.rb +2 -2
  401. data/lib/pdfrb.rb +25 -53
  402. data/pdfrb.gemspec +45 -0
  403. data/script/apply_fixes.sh +843 -0
  404. data/script/make_jpeg_fixture.rb +53 -0
  405. data/script/make_png_fixture.rb +25 -0
  406. metadata +312 -2
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Annotation
5
+ # Base annotation builder. Subclasses override +subtype+ and
6
+ # +default_fields+ to provide type-specific defaults. Each subclass
7
+ # calls +register_as+ at load time.
8
+ class Base
9
+ class << self
10
+ # @return [Symbol] the /Subtype value (e.g. :Link).
11
+ def subtype
12
+ raise NotImplementedError, "#{self} must define subtype"
13
+ end
14
+
15
+ # Extra fields to merge into the annotation dict.
16
+ # @return [Hash]
17
+ def default_fields
18
+ {}
19
+ end
20
+
21
+ # Create the annotation and attach it to the page's /Annots.
22
+ def create(document:, page:, rect:, **opts)
23
+ dict = base_dict(page: page, rect: rect, **opts).merge!(default_fields).merge!(type_overrides(opts))
24
+ annot = document.add(dict, type: Pdfrb::Model::Type::Annotation)
25
+ attach_to_page(page, annot)
26
+ annot
27
+ end
28
+
29
+ # Register this class in the Annotation registry.
30
+ def register_as(symbol = subtype)
31
+ Annotation.register(symbol, self)
32
+ self
33
+ end
34
+
35
+ private
36
+
37
+ def base_dict(page:, rect:, contents: nil, flags: 0, **)
38
+ {
39
+ Type: :Annot,
40
+ Subtype: subtype,
41
+ Rect: rect,
42
+ P: Pdfrb::Model::Reference.new(page.oid, page.gen),
43
+ Contents: contents,
44
+ F: flags,
45
+ }.compact
46
+ end
47
+
48
+ def type_overrides(opts)
49
+ overrides = {}
50
+ overrides[:C] = opts[:color] if opts.key?(:color)
51
+ overrides[:Border] = opts[:border] if opts.key?(:border)
52
+ overrides[:A] = opts[:action] if opts.key?(:action)
53
+ overrides[:Dest] = opts[:dest] if opts.key?(:dest)
54
+ overrides[:H] = opts[:highlight] if opts.key?(:highlight)
55
+ overrides[:BS] = opts[:border_style] if opts.key?(:border_style)
56
+ overrides[:QuadPoints] = opts[:quad_points] if opts.key?(:quad_points)
57
+ overrides[:T] = opts[:title] if opts.key?(:title)
58
+ overrides[:RC] = opts[:rich_contents] if opts.key?(:rich_contents)
59
+ overrides[:CreationDate] = opts[:created_at] if opts.key?(:created_at)
60
+ overrides[:M] = opts[:modified_at] if opts.key?(:modified_at)
61
+ overrides[:NM] = opts[:name] if opts.key?(:name)
62
+ overrides.compact
63
+ end
64
+
65
+ def attach_to_page(page, annot)
66
+ annots = page.value[:Annots]
67
+ ref = Pdfrb::Model::Reference.new(annot.oid, annot.gen)
68
+ if annots.nil?
69
+ page.value[:Annots] = [ref]
70
+ elsif annots.is_a?(::Array)
71
+ annots << ref
72
+ else
73
+ page.value[:Annots] = [annots, ref]
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Annotation
5
+ # Concrete annotation types (ISO 32000-2 §12.5.6). Each class
6
+ # defines its /Subtype and type-specific defaults, then registers
7
+ # itself via +register_as+.
8
+ #
9
+ # OCP: new annotation type = new class + register_as. No edits
10
+ # to existing code.
11
+
12
+ # Text annotation (sticky note). §12.5.6.4
13
+ class Text < Base
14
+ class << self
15
+ def subtype; :Text; end
16
+
17
+ def default_fields
18
+ { Name: :Comment }
19
+ end
20
+ end
21
+ register_as
22
+ end
23
+
24
+ # Link annotation (hyperlink). §12.5.6.5
25
+ class Link < Base
26
+ class << self
27
+ def subtype; :Link; end
28
+
29
+ def default_fields
30
+ { H: :I } # Invert highlight by default
31
+ end
32
+ end
33
+ register_as
34
+ end
35
+
36
+ # FreeText annotation (free-form text box). §12.5.6.6
37
+ class FreeText < Base
38
+ class << self
39
+ def subtype; :FreeText; end
40
+
41
+ def default_fields
42
+ { DA: "/Helv 0 Tf 0 g" }
43
+ end
44
+ end
45
+ register_as
46
+ end
47
+
48
+ # Stamp annotation (rubber stamp). §12.5.6.8
49
+ class Stamp < Base
50
+ class << self
51
+ def subtype; :Stamp; end
52
+
53
+ def default_fields
54
+ { Name: :Draft }
55
+ end
56
+ end
57
+ register_as
58
+ end
59
+
60
+ # Popup annotation. §12.5.6.13. Usually paired with a markup annot
61
+ # via the markup's /Popup key.
62
+ class Popup < Base
63
+ class << self
64
+ def subtype; :Popup; end
65
+
66
+ def default_fields
67
+ { Open: false }
68
+ end
69
+ end
70
+ register_as
71
+ end
72
+
73
+ # FileAttachment annotation (embedded file). §12.5.6.15
74
+ # Inspired by mn2pdf's FileAttachmentAnnotation.
75
+ class FileAttachment < Base
76
+ class << self
77
+ def subtype; :FileAttachment; end
78
+
79
+ def default_fields
80
+ { Name: :PushPin }
81
+ end
82
+ end
83
+ register_as
84
+ end
85
+
86
+ # Highlight (text markup). §12.5.6.10
87
+ class Highlight < Base
88
+ class << self
89
+ def subtype; :Highlight; end
90
+ end
91
+ register_as
92
+ end
93
+
94
+ # Underline (text markup). §12.5.6.10
95
+ class Underline < Base
96
+ class << self
97
+ def subtype; :Underline; end
98
+ end
99
+ register_as
100
+ end
101
+
102
+ # Squiggly (text markup). §12.5.6.10
103
+ class Squiggly < Base
104
+ class << self
105
+ def subtype; :Squiggly; end
106
+ end
107
+ register_as
108
+ end
109
+
110
+ # StrikeOut (text markup). §12.5.6.10
111
+ class StrikeOut < Base
112
+ class << self
113
+ def subtype; :StrikeOut; end
114
+ end
115
+ register_as
116
+ end
117
+
118
+ # Square (shape markup). §12.5.6.8
119
+ class Square < Base
120
+ class << self
121
+ def subtype; :Square; end
122
+ end
123
+ register_as
124
+ end
125
+
126
+ # Circle (shape markup). §12.5.6.8
127
+ class Circle < Base
128
+ class << self
129
+ def subtype; :Circle; end
130
+ end
131
+ register_as
132
+ end
133
+
134
+ # Line annotation. §12.5.6.7
135
+ class Line < Base
136
+ class << self
137
+ def subtype; :Line; end
138
+ end
139
+ register_as
140
+ end
141
+
142
+ # Polygon annotation. §12.5.6.9
143
+ class Polygon < Base
144
+ class << self
145
+ def subtype; :Polygon; end
146
+ end
147
+ register_as
148
+ end
149
+
150
+ # Polyline annotation. §12.5.6.9
151
+ class Polyline < Base
152
+ class << self
153
+ def subtype; :Polyline; end
154
+ end
155
+ register_as
156
+ end
157
+
158
+ # Ink annotation (freehand). §12.5.6.13
159
+ class Ink < Base
160
+ class << self
161
+ def subtype; :Ink; end
162
+ end
163
+ register_as
164
+ end
165
+
166
+ # Widget annotation (form field). §12.5.6.19
167
+ class Widget < Base
168
+ class << self
169
+ def subtype; :Widget; end
170
+ end
171
+ register_as
172
+ end
173
+
174
+ # Caret annotation. §12.5.6.11
175
+ class Caret < Base
176
+ class << self
177
+ def subtype; :Caret; end
178
+ end
179
+ register_as
180
+ end
181
+
182
+ # Redact annotation. §12.5.6.16
183
+ class Redact < Base
184
+ class << self
185
+ def subtype; :Redact; end
186
+ end
187
+ register_as
188
+ end
189
+
190
+ # Watermark annotation. §12.5.6.23 (PDF 2.0)
191
+ class Watermark < Base
192
+ class << self
193
+ def subtype; :Watermark; end
194
+ end
195
+ register_as
196
+ end
197
+
198
+ # PrinterMark annotation. §12.5.6.17
199
+ class PrinterMark < Base
200
+ class << self
201
+ def subtype; :PrinterMark; end
202
+ end
203
+ register_as
204
+ end
205
+
206
+ # Screen annotation. §12.5.6.18
207
+ class Screen < Base
208
+ class << self
209
+ def subtype; :Screen; end
210
+ end
211
+ register_as
212
+ end
213
+
214
+ # Sound annotation. §12.5.6.18
215
+ class Sound < Base
216
+ class << self
217
+ def subtype; :Sound; end
218
+ end
219
+ register_as
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ # Annotation types (ISO 32000-2 §12.5). Each subtype is a thin builder
5
+ # that produces a correctly-shaped annotation dictionary and registers
6
+ # itself in the +Annotation::REGISTRY+ for open/closed extensibility.
7
+ module Annotation
8
+ autoload :Base, "pdfrb/annotation/base"
9
+ autoload :Types, "pdfrb/annotation/types"
10
+ # Each annotation builder class lives in types.rb. Autoload from
11
+ # that file so direct class references work.
12
+ autoload :Text, "pdfrb/annotation/types"
13
+ autoload :Link, "pdfrb/annotation/types"
14
+ autoload :FreeText, "pdfrb/annotation/types"
15
+ autoload :Stamp, "pdfrb/annotation/types"
16
+ autoload :Popup, "pdfrb/annotation/types"
17
+ autoload :FileAttachment, "pdfrb/annotation/types"
18
+ autoload :Highlight, "pdfrb/annotation/types"
19
+ autoload :Underline, "pdfrb/annotation/types"
20
+ autoload :Squiggly, "pdfrb/annotation/types"
21
+ autoload :StrikeOut, "pdfrb/annotation/types"
22
+ autoload :Square, "pdfrb/annotation/types"
23
+ autoload :Circle, "pdfrb/annotation/types"
24
+ autoload :Line, "pdfrb/annotation/types"
25
+ autoload :Polygon, "pdfrb/annotation/types"
26
+ autoload :Polyline, "pdfrb/annotation/types"
27
+ autoload :Ink, "pdfrb/annotation/types"
28
+ autoload :Widget, "pdfrb/annotation/types"
29
+ autoload :Caret, "pdfrb/annotation/types"
30
+ autoload :Redact, "pdfrb/annotation/types"
31
+ autoload :Watermark, "pdfrb/annotation/types"
32
+ autoload :PrinterMark, "pdfrb/annotation/types"
33
+ autoload :Screen, "pdfrb/annotation/types"
34
+ autoload :Sound, "pdfrb/annotation/types"
35
+
36
+ class << self
37
+ def create(subtype, document:, page:, **opts)
38
+ ensure_loaded
39
+ klass = registry[subtype]
40
+ return build_fallback(subtype, document, page, opts) unless klass
41
+
42
+ klass.create(document: document, page: page, **opts)
43
+ end
44
+
45
+ def registry
46
+ @registry ||= {}
47
+ end
48
+
49
+ def register(subtype, klass)
50
+ registry[subtype] = klass
51
+ end
52
+
53
+ def [](subtype)
54
+ ensure_loaded
55
+ registry[subtype]
56
+ end
57
+
58
+ def subtypes
59
+ ensure_loaded
60
+ registry.keys
61
+ end
62
+
63
+ private
64
+
65
+ def ensure_loaded
66
+ return if @loaded
67
+
68
+ # Trigger the types.rb load which registers all subtypes.
69
+ Pdfrb::Annotation::Text
70
+ @loaded = true
71
+ end
72
+
73
+ def build_fallback(subtype, document, page, opts)
74
+ Base.create(subtype, document: document, page: page, **opts)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,216 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ module Pdfrb
6
+ module Appearance
7
+ # Generates /AP /N appearance streams for form fields and annotations.
8
+ # Each method creates a Form XObject with the field's visual
9
+ # representation and sets it as the /AP /N entry on the field.
10
+ #
11
+ # For PDF/A-4, /NeedAppearances must be false (or absent), so every
12
+ # field needs a pre-computed appearance stream.
13
+ class Generator
14
+ DEFAULT_BORDER_WIDTH = 1.0
15
+ DEFAULT_FONT_SIZE = 12
16
+ DEFAULT_PADDING = 3
17
+
18
+ attr_reader :document
19
+
20
+ def initialize(document)
21
+ @document = document
22
+ end
23
+
24
+ # Generate appearance for a text field.
25
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
26
+ # @param value [String] the text value to display.
27
+ # @param font_name [Symbol] resource name of the font.
28
+ # @param font_size [Integer] point size.
29
+ def text_field(field, value:, font_name: :Helv, font_size: DEFAULT_FONT_SIZE)
30
+ rect = field.value[:Rect]
31
+ return unless rect
32
+
33
+ form = build_form_xobject(rect) do |canvas|
34
+ draw_border(canvas, rect)
35
+ if value && !value.to_s.empty?
36
+ canvas.text(value.to_s,
37
+ at: [DEFAULT_PADDING, DEFAULT_PADDING],
38
+ font: font_name, size: font_size)
39
+ end
40
+ end
41
+
42
+ set_appearance(field, form)
43
+ end
44
+
45
+ # Generate appearance for a checkbox.
46
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
47
+ # @param checked [Boolean] whether the box is checked.
48
+ def checkbox(field, checked:)
49
+ rect = field.value[:Rect]
50
+ return unless rect
51
+
52
+ form = build_form_xobject(rect) do |canvas|
53
+ draw_border(canvas, rect)
54
+ if checked
55
+ draw_check(canvas, rect)
56
+ end
57
+ end
58
+
59
+ state_name = checked ? :Yes : :Off
60
+ set_appearance(field, form, state_name)
61
+ field.value[:AS] = state_name
62
+ end
63
+
64
+ # Generate appearance for a combo box (dropdown).
65
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
66
+ # @param value [String] the selected value.
67
+ # @param font_name [Symbol] resource name of the font.
68
+ # @param font_size [Integer] point size.
69
+ def combo(field, value:, font_name: :Helv, font_size: DEFAULT_FONT_SIZE)
70
+ text_field(field, value: value, font_name: font_name, font_size: font_size)
71
+ end
72
+
73
+ # Generate appearance for a push button.
74
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
75
+ # @param label [String] the button label.
76
+ # @param font_name [Symbol] resource name of the font.
77
+ def button(field, label:, font_name: :Helv)
78
+ rect = field.value[:Rect]
79
+ return unless rect
80
+
81
+ form = build_form_xobject(rect) do |canvas|
82
+ draw_border(canvas, rect)
83
+ if label
84
+ w = rect[2] - rect[0]
85
+ h = rect[3] - rect[1]
86
+ canvas.text(label,
87
+ at: [w / 3, h / 3],
88
+ font: font_name, size: DEFAULT_FONT_SIZE)
89
+ end
90
+ end
91
+
92
+ set_appearance(field, form)
93
+ end
94
+
95
+ # Generate appearance for a radio button.
96
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
97
+ # @param selected [String] the selected state name (e.g. :Yes).
98
+ # @param options [Array<String>] all possible state names.
99
+ def radio_button(field, selected:, options: [:Yes])
100
+ rect = field.value[:Rect]
101
+ return unless rect
102
+
103
+ options.each do |state|
104
+ form = build_form_xobject(rect) do |canvas|
105
+ draw_border(canvas, rect)
106
+ draw_radio_circle(canvas, rect, selected: state == selected)
107
+ end
108
+ set_appearance(field, form, state_name: state.to_sym)
109
+ end
110
+ field.value[:AS] = selected.to_sym
111
+ end
112
+
113
+ # Generate appearance for a list box field.
114
+ # @param field [Pdfrb::Model::Type::Annotation] the Widget/field.
115
+ # @param items [Array<String>] the list items to show.
116
+ # @param selected [Integer, nil] index of the selected item.
117
+ # @param font_name [Symbol] resource name of the font.
118
+ # @param font_size [Integer] point size.
119
+ def list_box(field, items:, selected: nil, font_name: :Helv,
120
+ font_size: DEFAULT_FONT_SIZE)
121
+ rect = field.value[:Rect]
122
+ return unless rect
123
+
124
+ form = build_form_xobject(rect) do |canvas|
125
+ draw_border(canvas, rect)
126
+ items.each_with_index do |item, i|
127
+ y_pos = (rect[3] - rect[1]) - DEFAULT_PADDING - ((i + 1) * font_size)
128
+ break if y_pos.negative?
129
+
130
+ if i == selected
131
+ w = rect[2] - rect[0]
132
+ canvas.fill_color([0.8, 0.8, 1.0])
133
+ canvas.rectangle(0, y_pos - 2, w, font_size + 4)
134
+ canvas.fill
135
+ canvas.fill_color([0, 0, 0])
136
+ end
137
+ canvas.text(item.to_s, at: [DEFAULT_PADDING, y_pos],
138
+ font: font_name, size: font_size)
139
+ end
140
+ end
141
+ set_appearance(field, form)
142
+ end
143
+
144
+ private
145
+
146
+ def build_form_xobject(rect)
147
+ x0, y0, x1, y1 = rect
148
+ form = document.create_form_xobject(
149
+ name: "AP",
150
+ bbox: [0, 0, x1 - x0, y1 - y0]
151
+ )
152
+ canvas = form.canvas
153
+ yield canvas
154
+ form.finalize!
155
+ form
156
+ end
157
+
158
+ def draw_border(canvas, rect)
159
+ w = rect[2] - rect[0]
160
+ h = rect[3] - rect[1]
161
+ canvas.line_width = 0.5
162
+ canvas.rectangle(0, 0, w, h)
163
+ canvas.stroke
164
+ end
165
+
166
+ def draw_radio_circle(canvas, rect, selected:)
167
+ w = rect[2] - rect[0]
168
+ h = rect[3] - rect[1]
169
+ r = ([w, h].min / 2) - 1
170
+ cx = w / 2
171
+ cy = h / 2
172
+ canvas.line_width = 1.0
173
+
174
+ # Approximate a circle with a rectangle for now (Canvas lacks arc).
175
+ canvas.rectangle(cx - r, cy - r, r * 2, r * 2)
176
+ canvas.stroke
177
+
178
+ if selected
179
+ canvas.line_width = 2.0
180
+ inner_r = r * 0.4
181
+ canvas.rectangle(cx - inner_r, cy - inner_r, inner_r * 2, inner_r * 2)
182
+ canvas.fill
183
+ end
184
+ end
185
+
186
+ def draw_check(canvas, rect)
187
+ w = rect[2] - rect[0]
188
+ h = rect[3] - rect[1]
189
+ m = [w * 0.2, h * 0.2].min
190
+ canvas.line_width = 1.5
191
+ canvas.line(m, m, w - m, h - m)
192
+ canvas.line(m, h - m, w - m, m)
193
+ canvas.stroke
194
+ end
195
+
196
+ def set_appearance(field, form, state_name = :Normal)
197
+ form_stream = form.stream
198
+ ref = Pdfrb::Model::Reference.new(form_stream.oid, form_stream.gen)
199
+
200
+ ap = field.value[:AP]
201
+ if ap.nil?
202
+ ap = {}
203
+ field.value[:AP] = ap
204
+ end
205
+
206
+ if state_name == :Normal
207
+ ap[:N] = ref
208
+ else
209
+ n_dict = ap[:N].is_a?(::Hash) ? ap[:N] : {}
210
+ n_dict[state_name] = ref
211
+ ap[:N] = n_dict
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ # Appearance stream generation (ISO 32000-2 §12.5.5). Generates
5
+ # /AP /N (normal appearance) streams for form fields and annotations
6
+ # using the Canvas API. Required for PDF/A-4 compliance (which
7
+ # prohibits /NeedAppearances).
8
+ module Appearance
9
+ autoload :Generator, "pdfrb/appearance/generator"
10
+ end
11
+ end
@@ -20,8 +20,8 @@ module Pdfrb
20
20
  new(name: name, version: version, fields: fields)
21
21
  end
22
22
 
23
- def each_field(&block)
24
- @fields.each(&block)
23
+ def each_field(&)
24
+ @fields.each(&)
25
25
  end
26
26
 
27
27
  def field_for(key)
@@ -68,7 +68,7 @@ module Pdfrb
68
68
  def walk(start, segments)
69
69
  cur = start
70
70
  segments.each do |seg|
71
- return nil unless cur.respond_to?(:[])
71
+ return nil unless cur.is_a?(Hash)
72
72
  next if seg.nil?
73
73
 
74
74
  cur = cur[seg.to_sym]
@@ -9,8 +9,18 @@ module Pdfrb
9
9
  module Functions
10
10
  @registry = {}
11
11
 
12
+ autoload :VersionPredicates, "pdfrb/arlington/predicate/functions/version"
13
+ autoload :PresencePredicates, "pdfrb/arlington/predicate/functions/presence"
14
+ autoload :LogicalPredicates, "pdfrb/arlington/predicate/functions/logical"
15
+ autoload :ArithmeticPredicates, "pdfrb/arlington/predicate/functions/arithmetic"
16
+ autoload :ReferencePredicates, "pdfrb/arlington/predicate/functions/reference"
17
+ autoload :FilePredicates, "pdfrb/arlington/predicate/functions/file"
18
+
12
19
  class << self
13
- attr_reader :registry
20
+ def registry
21
+ eager_load! unless @eager_loaded
22
+ @registry
23
+ end
14
24
 
15
25
  def register(name, &block)
16
26
  @registry[name.to_s] = block
@@ -19,16 +29,22 @@ module Pdfrb
19
29
  def clear!
20
30
  @registry.clear
21
31
  end
32
+
33
+ # Force-load all function groups so register calls fire.
34
+ # Idempotent.
35
+ def eager_load!
36
+ return if @eager_loaded
37
+
38
+ constants.each do |c|
39
+ const_get(c)
40
+ rescue NameError, LoadError
41
+ # Skip autoload targets that don't define a class
42
+ # or whose file doesn't exist yet.
43
+ end
44
+ @eager_loaded = true
45
+ end
22
46
  end
23
47
  end
24
48
  end
25
49
  end
26
50
  end
27
-
28
- # Load built-in function groups. Each calls Functions.register on load.
29
- require "pdfrb/arlington/predicate/functions/version"
30
- require "pdfrb/arlington/predicate/functions/presence"
31
- require "pdfrb/arlington/predicate/functions/logical"
32
- require "pdfrb/arlington/predicate/functions/arithmetic"
33
- require "pdfrb/arlington/predicate/functions/reference"
34
- require "pdfrb/arlington/predicate/functions/file"
@@ -12,11 +12,7 @@ module Pdfrb
12
12
  autoload :AST, "pdfrb/arlington/predicate/ast"
13
13
  autoload :Evaluator, "pdfrb/arlington/predicate/evaluator"
14
14
  autoload :Context, "pdfrb/arlington/predicate/context"
15
+ autoload :Functions, "pdfrb/arlington/predicate/functions"
15
16
  end
16
17
  end
17
18
  end
18
-
19
- # Eager-load the function registry so predicates are registered as
20
- # soon as the Predicate namespace is touched. (Functions.register is
21
- # called at the bottom of each functions/*.rb.)
22
- require "pdfrb/arlington/predicate/functions"