pdfrb 0.3.0 → 0.7.1

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 (422) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +51 -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 +61 -0
  23. data/data/pdfrb/afm/Courier-Bold.afm +342 -342
  24. data/data/pdfrb/afm/Courier-BoldOblique.afm +342 -342
  25. data/data/pdfrb/afm/Courier-Oblique.afm +342 -342
  26. data/data/pdfrb/afm/Courier.afm +342 -342
  27. data/data/pdfrb/afm/Helvetica-Bold.afm +2827 -2827
  28. data/data/pdfrb/afm/Helvetica-BoldOblique.afm +2827 -2827
  29. data/data/pdfrb/afm/Helvetica-Oblique.afm +3051 -3051
  30. data/data/pdfrb/afm/Helvetica.afm +3051 -3051
  31. data/data/pdfrb/afm/Symbol.afm +213 -213
  32. data/data/pdfrb/afm/Times-Bold.afm +2588 -2588
  33. data/data/pdfrb/afm/Times-BoldItalic.afm +2384 -2384
  34. data/data/pdfrb/afm/Times-Italic.afm +2667 -2667
  35. data/data/pdfrb/afm/Times-Roman.afm +2419 -2419
  36. data/data/pdfrb/afm/ZapfDingbats.afm +225 -225
  37. data/lib/pdfrb/action/base.rb +21 -0
  38. data/lib/pdfrb/action/types.rb +178 -0
  39. data/lib/pdfrb/action.rb +55 -0
  40. data/lib/pdfrb/annotation/base.rb +79 -0
  41. data/lib/pdfrb/annotation/types.rb +222 -0
  42. data/lib/pdfrb/annotation.rb +78 -0
  43. data/lib/pdfrb/appearance/generator.rb +216 -0
  44. data/lib/pdfrb/appearance.rb +11 -0
  45. data/lib/pdfrb/arlington/object_definition.rb +2 -2
  46. data/lib/pdfrb/arlington/predicate/evaluator.rb +1 -1
  47. data/lib/pdfrb/arlington/predicate/functions.rb +25 -9
  48. data/lib/pdfrb/arlington/predicate.rb +1 -5
  49. data/lib/pdfrb/cli/batch.rb +18 -0
  50. data/lib/pdfrb/cli/debug_info.rb +18 -0
  51. data/lib/pdfrb/cli/files.rb +16 -0
  52. data/lib/pdfrb/cli/fonts.rb +16 -0
  53. data/lib/pdfrb/cli/form.rb +18 -0
  54. data/lib/pdfrb/cli/image2pdf.rb +18 -0
  55. data/lib/pdfrb/cli/images.rb +34 -0
  56. data/lib/pdfrb/cli/info.rb +20 -0
  57. data/lib/pdfrb/cli/inspect.rb +18 -0
  58. data/lib/pdfrb/cli/merge.rb +18 -0
  59. data/lib/pdfrb/cli/modify.rb +18 -0
  60. data/lib/pdfrb/cli/optimize.rb +18 -0
  61. data/lib/pdfrb/cli/split.rb +21 -0
  62. data/lib/pdfrb/cli/watermark.rb +18 -0
  63. data/lib/pdfrb/cli.rb +291 -7
  64. data/lib/pdfrb/color/color_space.rb +259 -0
  65. data/lib/pdfrb/color/icc_profile.rb +90 -0
  66. data/lib/pdfrb/color.rb +12 -0
  67. data/lib/pdfrb/compare/comparator.rb +244 -0
  68. data/lib/pdfrb/compare/report.rb +78 -0
  69. data/lib/pdfrb/compare.rb +42 -0
  70. data/lib/pdfrb/composer.rb +161 -0
  71. data/lib/pdfrb/conformance/pdf_a.rb +317 -56
  72. data/lib/pdfrb/conformance/pdf_ua.rb +186 -29
  73. data/lib/pdfrb/conformance/pdf_x.rb +247 -0
  74. data/lib/pdfrb/conformance/rule.rb +78 -0
  75. data/lib/pdfrb/conformance/structure_elements.rb +174 -0
  76. data/lib/pdfrb/conformance/verapdf_bridge.rb +92 -0
  77. data/lib/pdfrb/conformance.rb +7 -3
  78. data/lib/pdfrb/content/canvas.rb +354 -72
  79. data/lib/pdfrb/content/color_space.rb +157 -0
  80. data/lib/pdfrb/content/hidden_text_detector.rb +167 -0
  81. data/lib/pdfrb/content/operator.rb +21 -1
  82. data/lib/pdfrb/content/operators/clipping.rb +36 -0
  83. data/lib/pdfrb/content/operators/graphics_state_params.rb +15 -0
  84. data/lib/pdfrb/content/operators/inline_image.rb +53 -0
  85. data/lib/pdfrb/content/operators.rb +22 -0
  86. data/lib/pdfrb/content/shading/base.rb +139 -0
  87. data/lib/pdfrb/content/shading.rb +17 -0
  88. data/lib/pdfrb/content/smart_text_extractor.rb +85 -0
  89. data/lib/pdfrb/content/tiling_pattern.rb +78 -0
  90. data/lib/pdfrb/content/transformation_matrix.rb +61 -0
  91. data/lib/pdfrb/content.rb +7 -26
  92. data/lib/pdfrb/destination/fit.rb +185 -0
  93. data/lib/pdfrb/destination.rb +13 -0
  94. data/lib/pdfrb/digital_signature/cms_handler.rb +22 -0
  95. data/lib/pdfrb/digital_signature/signing.rb +107 -11
  96. data/lib/pdfrb/digital_signature/timestamp_handler.rb +45 -0
  97. data/lib/pdfrb/digital_signature/verification.rb +88 -9
  98. data/lib/pdfrb/digital_signature/verification_result.rb +14 -0
  99. data/lib/pdfrb/digital_signature.rb +26 -2
  100. data/lib/pdfrb/document/annotations.rb +120 -3
  101. data/lib/pdfrb/document/associated_files.rb +104 -0
  102. data/lib/pdfrb/document/colors.rb +95 -0
  103. data/lib/pdfrb/document/destinations.rb +127 -5
  104. data/lib/pdfrb/document/display.rb +84 -0
  105. data/lib/pdfrb/document/fonts.rb +417 -45
  106. data/lib/pdfrb/document/form.rb +338 -0
  107. data/lib/pdfrb/document/graphics_state.rb +91 -0
  108. data/lib/pdfrb/document/images.rb +4 -4
  109. data/lib/pdfrb/document/info.rb +102 -0
  110. data/lib/pdfrb/document/layers.rb +62 -0
  111. data/lib/pdfrb/document/metadata.rb +12 -5
  112. data/lib/pdfrb/document/output_intents.rb +91 -0
  113. data/lib/pdfrb/document/page_labels.rb +80 -0
  114. data/lib/pdfrb/document/pages.rb +68 -19
  115. data/lib/pdfrb/document/portfolio.rb +119 -0
  116. data/lib/pdfrb/document/shadings.rb +159 -0
  117. data/lib/pdfrb/document/stamps.rb +68 -0
  118. data/lib/pdfrb/document/structure.rb +242 -0
  119. data/lib/pdfrb/document.rb +73 -4
  120. data/lib/pdfrb/encryption/identity.rb +13 -0
  121. data/lib/pdfrb/encryption/password_verification.rb +53 -8
  122. data/lib/pdfrb/encryption/security_handler.rb +8 -5
  123. data/lib/pdfrb/encryption/standard_security_handler.rb +154 -81
  124. data/lib/pdfrb/encryption.rb +17 -0
  125. data/lib/pdfrb/error.rb +2 -2
  126. data/lib/pdfrb/filter/brotli_decode.rb +32 -0
  127. data/lib/pdfrb/filter/ccitt_fax_decode.rb +12 -0
  128. data/lib/pdfrb/filter/crypt.rb +2 -2
  129. data/lib/pdfrb/filter/dct_decode.rb +18 -0
  130. data/lib/pdfrb/filter/flate_decode.rb +4 -18
  131. data/lib/pdfrb/filter/jbig2_decode.rb +12 -0
  132. data/lib/pdfrb/filter/jpx_decode.rb +18 -0
  133. data/lib/pdfrb/filter/lzw_decode.rb +3 -2
  134. data/lib/pdfrb/filter/png_predictor.rb +94 -0
  135. data/lib/pdfrb/filter.rb +26 -13
  136. data/lib/pdfrb/font/afm_parser.rb +50 -26
  137. data/lib/pdfrb/font/cmap/writer.rb +9 -0
  138. data/lib/pdfrb/font/encoding/win_ansi_encoding.rb +17 -0
  139. data/lib/pdfrb/font/encoding.rb +32 -3
  140. data/lib/pdfrb/font/metrics_helper.rb +121 -0
  141. data/lib/pdfrb/font/true_type/file.rb +10 -1
  142. data/lib/pdfrb/font/true_type/glyf.rb +82 -0
  143. data/lib/pdfrb/font/true_type/kern.rb +58 -0
  144. data/lib/pdfrb/font/true_type/loca.rb +42 -0
  145. data/lib/pdfrb/font/true_type/maxp.rb +44 -0
  146. data/lib/pdfrb/font/true_type/name.rb +53 -0
  147. data/lib/pdfrb/font/true_type/post.rb +93 -0
  148. data/lib/pdfrb/font/true_type/subsetter.rb +3 -5
  149. data/lib/pdfrb/font/true_type/wrapper.rb +102 -0
  150. data/lib/pdfrb/font/true_type.rb +7 -0
  151. data/lib/pdfrb/font.rb +2 -0
  152. data/lib/pdfrb/font_loader/from_configuration.rb +19 -0
  153. data/lib/pdfrb/font_loader/from_file.rb +20 -0
  154. data/lib/pdfrb/font_loader/standard14.rb +20 -0
  155. data/lib/pdfrb/font_loader/variant_from_name.rb +36 -0
  156. data/lib/pdfrb/font_loader.rb +4 -0
  157. data/lib/pdfrb/font_resolver.rb +138 -0
  158. data/lib/pdfrb/image/audit.rb +94 -0
  159. data/lib/pdfrb/image/downsampler.rb +124 -0
  160. data/lib/pdfrb/image.rb +13 -0
  161. data/lib/pdfrb/image_loader/jpeg.rb +39 -58
  162. data/lib/pdfrb/image_loader/png.rb +82 -251
  163. data/lib/pdfrb/layout/bidi.rb +198 -0
  164. data/lib/pdfrb/layout/box.rb +49 -0
  165. data/lib/pdfrb/layout/box_fitter.rb +54 -0
  166. data/lib/pdfrb/layout/column_box.rb +71 -0
  167. data/lib/pdfrb/layout/container_box.rb +45 -0
  168. data/lib/pdfrb/layout/frame.rb +67 -0
  169. data/lib/pdfrb/layout/image_box.rb +44 -0
  170. data/lib/pdfrb/layout/inline_box.rb +25 -0
  171. data/lib/pdfrb/layout/line.rb +55 -0
  172. data/lib/pdfrb/layout/list_box.rb +87 -0
  173. data/lib/pdfrb/layout/numeric_refinements.rb +43 -0
  174. data/lib/pdfrb/layout/page_style.rb +65 -0
  175. data/lib/pdfrb/layout/style.rb +62 -0
  176. data/lib/pdfrb/layout/table_box.rb +66 -0
  177. data/lib/pdfrb/layout/text_box.rb +38 -0
  178. data/lib/pdfrb/layout/text_fragment.rb +45 -0
  179. data/lib/pdfrb/layout/text_layouter.rb +123 -0
  180. data/lib/pdfrb/layout.rb +28 -0
  181. data/lib/pdfrb/linearization/hint_stream.rb +93 -0
  182. data/lib/pdfrb/linearization/writer.rb +259 -0
  183. data/lib/pdfrb/linearization.rb +21 -0
  184. data/lib/pdfrb/model/cos/dictionary.rb +12 -0
  185. data/lib/pdfrb/model/pdf_array.rb +2 -2
  186. data/lib/pdfrb/model/type/action.rb +42 -0
  187. data/lib/pdfrb/model/type/action_go_to_3d_view.rb +14 -0
  188. data/lib/pdfrb/model/type/action_go_to_dp.rb +16 -0
  189. data/lib/pdfrb/model/type/action_go_to_r.rb +26 -0
  190. data/lib/pdfrb/model/type/action_goto.rb +34 -0
  191. data/lib/pdfrb/model/type/action_hide.rb +26 -0
  192. data/lib/pdfrb/model/type/action_import_data.rb +18 -0
  193. data/lib/pdfrb/model/type/action_java_script.rb +18 -0
  194. data/lib/pdfrb/model/type/action_launch.rb +22 -0
  195. data/lib/pdfrb/model/type/action_movie.rb +22 -0
  196. data/lib/pdfrb/model/type/action_named.rb +23 -0
  197. data/lib/pdfrb/model/type/action_nop.rb +12 -0
  198. data/lib/pdfrb/model/type/action_rendition.rb +28 -0
  199. data/lib/pdfrb/model/type/action_reset_form.rb +22 -0
  200. data/lib/pdfrb/model/type/action_rich_media_execute.rb +17 -0
  201. data/lib/pdfrb/model/type/action_set_ocg_state.rb +32 -0
  202. data/lib/pdfrb/model/type/action_set_state.rb +14 -0
  203. data/lib/pdfrb/model/type/action_sound_action.rb +23 -0
  204. data/lib/pdfrb/model/type/action_submit_form.rb +64 -0
  205. data/lib/pdfrb/model/type/action_thread.rb +23 -0
  206. data/lib/pdfrb/model/type/action_trans.rb +30 -0
  207. data/lib/pdfrb/model/type/action_uri.rb +30 -0
  208. data/lib/pdfrb/model/type/af_embedded_file.rb +11 -0
  209. data/lib/pdfrb/model/type/af_file_specification.rb +34 -0
  210. data/lib/pdfrb/model/type/annotation.rb +49 -10
  211. data/lib/pdfrb/model/type/appearance.rb +41 -0
  212. data/lib/pdfrb/model/type/appearance_characteristics.rb +36 -0
  213. data/lib/pdfrb/model/type/appearance_generator.rb +22 -0
  214. data/lib/pdfrb/model/type/appearance_trap_net.rb +84 -0
  215. data/lib/pdfrb/model/type/border_effect.rb +25 -0
  216. data/lib/pdfrb/model/type/border_styling.rb +38 -0
  217. data/lib/pdfrb/model/type/box_color_info.rb +21 -0
  218. data/lib/pdfrb/model/type/box_style.rb +19 -0
  219. data/lib/pdfrb/model/type/button.rb +17 -0
  220. data/lib/pdfrb/model/type/cal_gray.rb +17 -0
  221. data/lib/pdfrb/model/type/cal_rgb.rb +22 -0
  222. data/lib/pdfrb/model/type/caret_annotation.rb +21 -0
  223. data/lib/pdfrb/model/type/catalog.rb +99 -16
  224. data/lib/pdfrb/model/type/choice.rb +21 -0
  225. data/lib/pdfrb/model/type/cid_font.rb +52 -1
  226. data/lib/pdfrb/model/type/cid_font_descriptor_metrics.rb +28 -0
  227. data/lib/pdfrb/model/type/cid_system_info.rb +28 -0
  228. data/lib/pdfrb/model/type/circle_annotation.rb +20 -0
  229. data/lib/pdfrb/model/type/collection.rb +27 -0
  230. data/lib/pdfrb/model/type/collection_field.rb +24 -0
  231. data/lib/pdfrb/model/type/collection_item.rb +19 -0
  232. data/lib/pdfrb/model/type/collection_schema.rb +25 -0
  233. data/lib/pdfrb/model/type/collection_sort.rb +13 -0
  234. data/lib/pdfrb/model/type/crypt_filter.rb +58 -0
  235. data/lib/pdfrb/model/type/device_n.rb +37 -0
  236. data/lib/pdfrb/model/type/device_n_mixing_hints.rb +17 -0
  237. data/lib/pdfrb/model/type/device_n_process.rb +13 -0
  238. data/lib/pdfrb/model/type/doc_mdp_transform_parameters.rb +21 -0
  239. data/lib/pdfrb/model/type/document_security_store.rb +55 -0
  240. data/lib/pdfrb/model/type/embedded_file.rb +19 -0
  241. data/lib/pdfrb/model/type/embedded_file_parameter.rb +48 -0
  242. data/lib/pdfrb/model/type/encryption_public_key.rb +38 -0
  243. data/lib/pdfrb/model/type/encryption_standard.rb +68 -0
  244. data/lib/pdfrb/model/type/field_mdp_transform_parameters.rb +26 -0
  245. data/lib/pdfrb/model/type/file_attachment_annotation.rb +29 -0
  246. data/lib/pdfrb/model/type/file_spec_ef.rb +22 -0
  247. data/lib/pdfrb/model/type/file_spec_rf.rb +21 -0
  248. data/lib/pdfrb/model/type/file_specification.rb +43 -0
  249. data/lib/pdfrb/model/type/file_trailer.rb +54 -0
  250. data/lib/pdfrb/model/type/font.rb +73 -2
  251. data/lib/pdfrb/model/type/font_cid_type0.rb +17 -0
  252. data/lib/pdfrb/model/type/font_cid_type2.rb +17 -0
  253. data/lib/pdfrb/model/type/font_descriptor.rb +47 -0
  254. data/lib/pdfrb/model/type/font_descriptor_cid_type0.rb +15 -0
  255. data/lib/pdfrb/model/type/font_descriptor_cid_type2.rb +15 -0
  256. data/lib/pdfrb/model/type/font_encoding.rb +47 -0
  257. data/lib/pdfrb/model/type/font_file.rb +28 -0
  258. data/lib/pdfrb/model/type/font_file2.rb +32 -0
  259. data/lib/pdfrb/model/type/font_file3.rb +23 -0
  260. data/lib/pdfrb/model/type/font_multiple_master.rb +60 -0
  261. data/lib/pdfrb/model/type/font_true_type.rb +1 -1
  262. data/lib/pdfrb/model/type/font_type0.rb +1 -1
  263. data/lib/pdfrb/model/type/font_type1.rb +1 -1
  264. data/lib/pdfrb/model/type/font_type3.rb +1 -1
  265. data/lib/pdfrb/model/type/form_field.rb +73 -0
  266. data/lib/pdfrb/model/type/free_text_annotation.rb +37 -0
  267. data/lib/pdfrb/model/type/function.rb +42 -0
  268. data/lib/pdfrb/model/type/function_exponential.rb +31 -0
  269. data/lib/pdfrb/model/type/function_postscript.rb +25 -0
  270. data/lib/pdfrb/model/type/function_sampled.rb +55 -0
  271. data/lib/pdfrb/model/type/function_stitching.rb +33 -0
  272. data/lib/pdfrb/model/type/generic_appearance.rb +40 -0
  273. data/lib/pdfrb/model/type/graphics_state_parameter.rb +69 -0
  274. data/lib/pdfrb/model/type/halftone.rb +21 -0
  275. data/lib/pdfrb/model/type/halftone_type1.rb +17 -0
  276. data/lib/pdfrb/model/type/halftone_type10.rb +16 -0
  277. data/lib/pdfrb/model/type/halftone_type16.rb +11 -0
  278. data/lib/pdfrb/model/type/halftone_type5.rb +24 -0
  279. data/lib/pdfrb/model/type/halftone_type6.rb +16 -0
  280. data/lib/pdfrb/model/type/highlight_annotation.rb +11 -0
  281. data/lib/pdfrb/model/type/icc_based_color_space.rb +24 -0
  282. data/lib/pdfrb/model/type/icon_fit.rb +31 -0
  283. data/lib/pdfrb/model/type/indexed.rb +32 -0
  284. data/lib/pdfrb/model/type/info.rb +44 -0
  285. data/lib/pdfrb/model/type/ink_annotation.rb +29 -0
  286. data/lib/pdfrb/model/type/interactive_form.rb +36 -0
  287. data/lib/pdfrb/model/type/interior_color.rb +12 -0
  288. data/lib/pdfrb/model/type/jbig2_globals.rb +15 -0
  289. data/lib/pdfrb/model/type/lab.rb +27 -0
  290. data/lib/pdfrb/model/type/line_annotation.rb +44 -0
  291. data/lib/pdfrb/model/type/line_ending_styling.rb +39 -0
  292. data/lib/pdfrb/model/type/link_annotation.rb +41 -0
  293. data/lib/pdfrb/model/type/link_appearance.rb +9 -0
  294. data/lib/pdfrb/model/type/mark_information.rb +23 -0
  295. data/lib/pdfrb/model/type/marked_content_reference.rb +24 -0
  296. data/lib/pdfrb/model/type/markup_annotation.rb +36 -0
  297. data/lib/pdfrb/model/type/mdp_dict.rb +28 -0
  298. data/lib/pdfrb/model/type/measure.rb +39 -0
  299. data/lib/pdfrb/model/type/media_clip.rb +28 -0
  300. data/lib/pdfrb/model/type/media_offset.rb +106 -0
  301. data/lib/pdfrb/model/type/metadata.rb +27 -3
  302. data/lib/pdfrb/model/type/misc_helpers.rb +75 -0
  303. data/lib/pdfrb/model/type/movie.rb +28 -0
  304. data/lib/pdfrb/model/type/names.rb +51 -0
  305. data/lib/pdfrb/model/type/namespace.rb +27 -0
  306. data/lib/pdfrb/model/type/object_reference.rb +31 -0
  307. data/lib/pdfrb/model/type/object_stream.rb +38 -0
  308. data/lib/pdfrb/model/type/opt_content_ext.rb +94 -0
  309. data/lib/pdfrb/model/type/opt_content_page_element.rb +18 -0
  310. data/lib/pdfrb/model/type/optional_content_config.rb +56 -0
  311. data/lib/pdfrb/model/type/optional_content_group.rb +35 -10
  312. data/lib/pdfrb/model/type/optional_content_membership.rb +36 -2
  313. data/lib/pdfrb/model/type/optional_content_properties.rb +16 -1
  314. data/lib/pdfrb/model/type/outline.rb +40 -6
  315. data/lib/pdfrb/model/type/outline_item.rb +45 -0
  316. data/lib/pdfrb/model/type/output_intent.rb +30 -0
  317. data/lib/pdfrb/model/type/page.rb +127 -0
  318. data/lib/pdfrb/model/type/page_label.rb +68 -0
  319. data/lib/pdfrb/model/type/page_piece_info.rb +58 -0
  320. data/lib/pdfrb/model/type/page_tree_node.rb +51 -16
  321. data/lib/pdfrb/model/type/page_tree_node_root.rb +15 -0
  322. data/lib/pdfrb/model/type/pattern.rb +16 -0
  323. data/lib/pdfrb/model/type/pattern_shading.rb +25 -0
  324. data/lib/pdfrb/model/type/pattern_tiling.rb +25 -0
  325. data/lib/pdfrb/model/type/polygon_annotation.rb +29 -0
  326. data/lib/pdfrb/model/type/polygon_polyline.rb +14 -0
  327. data/lib/pdfrb/model/type/polyline_annotation.rb +29 -0
  328. data/lib/pdfrb/model/type/popup_annotation.rb +20 -0
  329. data/lib/pdfrb/model/type/printer_mark_annotation.rb +13 -0
  330. data/lib/pdfrb/model/type/redact_annotation.rb +28 -0
  331. data/lib/pdfrb/model/type/rendition.rb +31 -0
  332. data/lib/pdfrb/model/type/resources.rb +59 -14
  333. data/lib/pdfrb/model/type/rich_media_activation.rb +24 -0
  334. data/lib/pdfrb/model/type/rich_media_animation.rb +25 -0
  335. data/lib/pdfrb/model/type/rich_media_annotation.rb +18 -0
  336. data/lib/pdfrb/model/type/rich_media_command.rb +19 -0
  337. data/lib/pdfrb/model/type/rich_media_configuration.rb +32 -0
  338. data/lib/pdfrb/model/type/rich_media_content.rb +28 -0
  339. data/lib/pdfrb/model/type/rich_media_cue_point.rb +18 -0
  340. data/lib/pdfrb/model/type/rich_media_deactivation.rb +17 -0
  341. data/lib/pdfrb/model/type/rich_media_instance.rb +33 -0
  342. data/lib/pdfrb/model/type/rich_media_presentation.rb +29 -0
  343. data/lib/pdfrb/model/type/rich_media_settings.rb +33 -0
  344. data/lib/pdfrb/model/type/rich_media_window.rb +20 -0
  345. data/lib/pdfrb/model/type/screen_annotation.rb +19 -0
  346. data/lib/pdfrb/model/type/separation.rb +25 -0
  347. data/lib/pdfrb/model/type/sig_field_lock.rb +25 -0
  348. data/lib/pdfrb/model/type/sig_field_seed_value.rb +25 -0
  349. data/lib/pdfrb/model/type/signature.rb +65 -0
  350. data/lib/pdfrb/model/type/signature_build.rb +86 -0
  351. data/lib/pdfrb/model/type/signature_field.rb +17 -0
  352. data/lib/pdfrb/model/type/software_identifier.rb +19 -0
  353. data/lib/pdfrb/model/type/sound.rb +38 -0
  354. data/lib/pdfrb/model/type/sound_annotation.rb +21 -0
  355. data/lib/pdfrb/model/type/square_annotation.rb +24 -0
  356. data/lib/pdfrb/model/type/square_circle.rb +13 -0
  357. data/lib/pdfrb/model/type/squiggly_annotation.rb +11 -0
  358. data/lib/pdfrb/model/type/stamp_annotation.rb +19 -0
  359. data/lib/pdfrb/model/type/strikeout_annotation.rb +11 -0
  360. data/lib/pdfrb/model/type/struct_elem.rb +75 -0
  361. data/lib/pdfrb/model/type/struct_tree_root.rb +34 -0
  362. data/lib/pdfrb/model/type/structure_attributes.rb +44 -0
  363. data/lib/pdfrb/model/type/structure_element_kid.rb +33 -0
  364. data/lib/pdfrb/model/type/text_annotation.rb +25 -0
  365. data/lib/pdfrb/model/type/text_appearance.rb +9 -0
  366. data/lib/pdfrb/model/type/text_field.rb +21 -0
  367. data/lib/pdfrb/model/type/text_markup_annotation.rb +30 -0
  368. data/lib/pdfrb/model/type/three_d_activation.rb +32 -0
  369. data/lib/pdfrb/model/type/three_d_animation_style.rb +24 -0
  370. data/lib/pdfrb/model/type/three_d_background.rb +28 -0
  371. data/lib/pdfrb/model/type/three_d_cross_section.rb +25 -0
  372. data/lib/pdfrb/model/type/three_d_lighting_scheme.rb +26 -0
  373. data/lib/pdfrb/model/type/three_d_measure.rb +20 -0
  374. data/lib/pdfrb/model/type/three_d_measure_3dc.rb +23 -0
  375. data/lib/pdfrb/model/type/three_d_measure_ad3.rb +14 -0
  376. data/lib/pdfrb/model/type/three_d_measure_ld3.rb +14 -0
  377. data/lib/pdfrb/model/type/three_d_measure_pd3.rb +20 -0
  378. data/lib/pdfrb/model/type/three_d_measure_rd3.rb +14 -0
  379. data/lib/pdfrb/model/type/three_d_node.rb +37 -0
  380. data/lib/pdfrb/model/type/three_d_reference.rb +21 -0
  381. data/lib/pdfrb/model/type/three_d_render_mode.rb +34 -0
  382. data/lib/pdfrb/model/type/three_d_stream.rb +48 -0
  383. data/lib/pdfrb/model/type/three_d_units.rb +18 -0
  384. data/lib/pdfrb/model/type/three_d_view.rb +40 -0
  385. data/lib/pdfrb/model/type/to_unicode_cmap_stream.rb +23 -0
  386. data/lib/pdfrb/model/type/transition.rb +68 -0
  387. data/lib/pdfrb/model/type/underline_annotation.rb +11 -0
  388. data/lib/pdfrb/model/type/ur_transform_parameters.rb +33 -0
  389. data/lib/pdfrb/model/type/uri_dict.rb +18 -0
  390. data/lib/pdfrb/model/type/url_alias.rb +19 -0
  391. data/lib/pdfrb/model/type/variable_text_field.rb +47 -0
  392. data/lib/pdfrb/model/type/viewer_preferences.rb +42 -0
  393. data/lib/pdfrb/model/type/watermark_annotation.rb +13 -0
  394. data/lib/pdfrb/model/type/widget_annotation.rb +48 -0
  395. data/lib/pdfrb/model/type/widget_appearance.rb +9 -0
  396. data/lib/pdfrb/model/type/xobject_form.rb +41 -0
  397. data/lib/pdfrb/model/type/xobject_image.rb +56 -0
  398. data/lib/pdfrb/model/type/xref_stream.rb +37 -0
  399. data/lib/pdfrb/model/type.rb +289 -6
  400. data/lib/pdfrb/serializer.rb +2 -2
  401. data/lib/pdfrb/source/tokenizer.rb +0 -2
  402. data/lib/pdfrb/task/benchmark.rb +83 -0
  403. data/lib/pdfrb/task/extract_text.rb +1 -1
  404. data/lib/pdfrb/task/generate_corpus.rb +130 -0
  405. data/lib/pdfrb/task/memory_profile.rb +84 -0
  406. data/lib/pdfrb/task/optimize.rb +97 -7
  407. data/lib/pdfrb/task/regenerate_appearances.rb +98 -0
  408. data/lib/pdfrb/task.rb +4 -3
  409. data/lib/pdfrb/test_utils.rb +112 -0
  410. data/lib/pdfrb/validator.rb +82 -0
  411. data/lib/pdfrb/version.rb +1 -1
  412. data/lib/pdfrb/writer.rb +117 -27
  413. data/lib/pdfrb/xmp/packet.rb +122 -0
  414. data/lib/pdfrb/xmp/schemas.rb +96 -0
  415. data/lib/pdfrb/xmp.rb +44 -0
  416. data/lib/pdfrb/xref_section.rb +2 -2
  417. data/lib/pdfrb.rb +24 -54
  418. data/pdfrb.gemspec +45 -0
  419. data/script/apply_fixes.sh +843 -0
  420. data/script/make_jpeg_fixture.rb +53 -0
  421. data/script/make_png_fixture.rb +25 -0
  422. metadata +319 -4
@@ -0,0 +1,53 @@
1
+ # PROPOSAL: Missing `require "stringio"` in Fonts
2
+
3
+ ## Summary
4
+
5
+ `Pdfrb::Document::Fonts` references `StringIO` without requiring it.
6
+ When pdfrb is loaded without another gem that happens to require
7
+ `stringio` first, `Fonts#register_font` raises `NameError`.
8
+
9
+ ## Bug description
10
+
11
+ In `fonts.rb`, line 204:
12
+
13
+ ```ruby
14
+ def register_font(resource, name, name_or_io, **opts)
15
+ font_dict = if name_or_io.is_a?(IO) || name_or_io.is_a?(StringIO)
16
+ # ^^^^^^^^ NameError if stringio not loaded
17
+ ```
18
+
19
+ Line 207 also uses `StringIO`:
20
+
21
+ ```ruby
22
+ io = StringIO.new(File.binread(name_or_io))
23
+ ```
24
+
25
+ There is no `require "stringio"` at the top of `fonts.rb`.
26
+
27
+ ## Reproduction
28
+
29
+ ```ruby
30
+ # In a clean Ruby process where stringio hasn't been loaded:
31
+ require "pdfrb"
32
+ doc = Pdfrb::Document.new
33
+ doc.fonts.add("/path/to/font.ttf")
34
+ # NameError: uninitialized constant Pdfrb::Document::Fonts::StringIO
35
+ ```
36
+
37
+ In practice, other gems often load `stringio` first, masking this bug.
38
+ But it surfaces in minimal environments.
39
+
40
+ ## Proposed fix
41
+
42
+ Add to the top of `lib/pdfrb/document/fonts.rb`:
43
+
44
+ ```ruby
45
+ require "stringio"
46
+ ```
47
+
48
+ Or add it to `lib/pdfrb.rb` (the main entry point).
49
+
50
+ ## Priority
51
+
52
+ Low — easy one-line fix, but rare in practice (other gems usually
53
+ load stringio first).
@@ -0,0 +1,102 @@
1
+ # PROPOSAL: StructTreeRoot for tagged PDF (PDF/UA)
2
+
3
+ ## Summary
4
+
5
+ Add `Document#structure` facade for building PDF structure trees
6
+ (`/StructTreeRoot`), enabling tagged PDF output for accessibility
7
+ (PDF/UA, WCAG 2.1, Section 508 compliance).
8
+
9
+ ## Motivation
10
+
11
+ pdfrb 0.3.0 already has Canvas tagged-content support (`tagged`,
12
+ `artifact`, `marked_content`), but lacks the `/StructTreeRoot` assembly
13
+ that ties tagged content sequences into a navigable structure tree.
14
+ Without StructTreeRoot, screen readers cannot navigate the document.
15
+
16
+ The `idml` gem needs tagged PDF output for:
17
+ - Government documents (Section 508 compliance)
18
+ - Academic publishing (WCAG 2.1 AA)
19
+ - Accessible PDF/A (PDF/A-1a, PDF/A-2a)
20
+
21
+ ## Proposed API
22
+
23
+ ```ruby
24
+ # Build structure tree
25
+ doc.structure.add_element(:H1, text: "Chapter 1", page: 0, mcid: 0)
26
+ doc.structure.add_element(:P, text: "Body text...", page: 0, mcid: 1)
27
+ doc.structure.add_element(:Figure, alt: "Diagram", page: 1, mcid: 2)
28
+ doc.structure.add_element(:TR, children: [
29
+ doc.structure.element(:TH, text: "Name"),
30
+ doc.structure.element(:TH, text: "Value"),
31
+ ])
32
+
33
+ # Mark content in the Canvas
34
+ page.canvas.tagged(:H1, mcid: 0) { canvas.text("Chapter 1", ...) }
35
+ page.canvas.tagged(:P, mcid: 1) { canvas.text("Body text...", ...) }
36
+
37
+ # Build and attach to Catalog
38
+ doc.structure.build!
39
+ ```
40
+
41
+ ## PDF structure
42
+
43
+ ```
44
+ /StructTreeRoot
45
+ /Type /StructTreeRoot
46
+ /K [ struct_elem_0 struct_elem_1 ... ]
47
+ /ParentTree << /Nums [ 0 [elem_ref] 1 [elem_ref] ... ] >>
48
+ /ParentTreeNextKey N
49
+
50
+ /StructElem (each)
51
+ /Type /StructElem
52
+ /S /H1 (structure type: H1, P, Figure, TR, TH, TD, ...)
53
+ /P struct_tree_root (parent)
54
+ /K mcid_or_ref (content reference)
55
+ /Pg page_ref (page containing the content)
56
+ /Alt (alt text) (for figures)
57
+ ```
58
+
59
+ ## Implementation outline
60
+
61
+ ```ruby
62
+ class Pdfrb::Document
63
+ class Structure
64
+ attr_reader :document, :elements
65
+
66
+ def initialize(document)
67
+ @document = document
68
+ @elements = []
69
+ @next_mcid = 0
70
+ end
71
+
72
+ def add_element(type, text: nil, alt: nil, page:, mcid:, **opts)
73
+ elem = StructElement.new(type, text:, alt:, page:, mcid:, **opts)
74
+ @elements << elem
75
+ elem
76
+ end
77
+
78
+ def next_mcid
79
+ id = @next_mcid
80
+ @next_mcid += 1
81
+ id
82
+ end
83
+
84
+ # Build /StructTreeRoot and attach to Catalog.
85
+ def build!
86
+ return if @elements.empty?
87
+
88
+ root_id = allocate_struct_tree_root
89
+ @elements.each { |e| e.build_object(document, root_id) }
90
+ build_parent_tree(root_id)
91
+ document.catalog[:StructTreeRoot] = Pdfrb::Model::Reference.new(root_id)
92
+ document.catalog[:MarkInfo] = { Type: :MarkInfo, Marked: true }
93
+ end
94
+ end
95
+ end
96
+ ```
97
+
98
+ ## Priority
99
+
100
+ Medium — the Canvas already supports marked content (`BMC`/`EMC`), so
101
+ this is the missing piece for full tagged PDF. Not blocking for basic
102
+ rendering but essential for accessibility compliance.
@@ -0,0 +1,93 @@
1
+ # PROPOSAL: Canvas text measurement API
2
+
3
+ ## Summary
4
+
5
+ Add `Document#fonts#measure_text(text, font:, size:)` returning the
6
+ rendered width in points. Enables callers to do line breaking, text
7
+ centering, and frame-fitting without a separate font metrics library.
8
+
9
+ ## Motivation
10
+
11
+ The `idml` gem has its own text layout engine (`Idml::TextEngine`) with
12
+ a `FontMetrics` class that reads TTF tables via Fontisan. This is
13
+ necessary because pdfrb doesn't expose text measurement. If pdfrb
14
+ provided this, the idml gem could:
15
+
16
+ 1. Remove the entire `Idml::TextEngine::FontMetrics` class (~200 lines).
17
+ 2. Remove the `Fontisan` dependency.
18
+ 3. Use pdfrb's own font data (which it already loads for `encode_text`).
19
+
20
+ ## Proposed API
21
+
22
+ ```ruby
23
+ # Measure the rendered width of a text string at a given font and size.
24
+ # @param text [String] the text to measure.
25
+ # @param font [Symbol] font resource name from Fonts#add.
26
+ # @param size [Float] font size in points.
27
+ # @return [Float] width in points.
28
+ def measure_text(text, font:, size:)
29
+ afm = afm_for_font(font)
30
+ return 0.0 unless afm
31
+
32
+ scale = size / 1000.0
33
+ text.each_char.sum { |char| (afm.widths[char] || 0) * scale }
34
+ end
35
+
36
+ # Get font metrics for a registered font.
37
+ # @param font [Symbol] font resource name.
38
+ # @return [Hash] { ascent:, descent:, cap_height:, x_height:, units_per_em: }
39
+ def metrics_for(font)
40
+ afm = afm_for_font(font)
41
+ return {} unless afm
42
+
43
+ {
44
+ ascent: afm.ascent,
45
+ descent: afm.descent,
46
+ cap_height: afm.cap_height,
47
+ x_height: afm.x_height,
48
+ units_per_em: 1000,
49
+ }
50
+ end
51
+ ```
52
+
53
+ ## Implementation notes
54
+
55
+ pdfrb already loads AFM (Adobe Font Metrics) data for the 14 standard
56
+ Type1 fonts (`AFM_DIR`). For embedded TrueType fonts, the glyph widths
57
+ are in the font's `hmtx` table, which pdfrb parses during font loading.
58
+
59
+ The `measure_text` method would:
60
+ 1. For standard fonts: use AFM width data (already loaded).
61
+ 2. For embedded TrueType: use the glyph widths from `hmtx`.
62
+ 3. For unknown fonts: return 0.0 or raise.
63
+
64
+ ## Usage example
65
+
66
+ ```ruby
67
+ font = doc.fonts.add("Helvetica")
68
+ width = doc.fonts.measure_text("Hello, World!", font: font, size: 12)
69
+ # => ~63.0 (points)
70
+
71
+ # Line breaking
72
+ frame_width = 200
73
+ words = text.split
74
+ line = +""
75
+ lines = []
76
+ words.each do |word|
77
+ test = "#{line} #{word}".strip
78
+ if doc.fonts.measure_text(test, font: font, size: 12) <= frame_width
79
+ line = test
80
+ else
81
+ lines << line
82
+ line = word
83
+ end
84
+ end
85
+ lines << line if line.any?
86
+ ```
87
+
88
+ ## Priority
89
+
90
+ Medium — the idml gem has a workaround (its own FontMetrics), but
91
+ centralizing measurement in pdfrb reduces duplication and eliminates
92
+ the Fontisan dependency for idml consumers who don't need standalone
93
+ font parsing.
@@ -0,0 +1,112 @@
1
+ # PROPOSAL: Fix TTF table parsing — table() returns raw bytes instead of parsed objects
2
+
3
+ ## Summary
4
+
5
+ `Pdfrb::Font::TrueType::File#table("cmap")` returns a raw `String` of
6
+ table bytes instead of a parsed table object. This breaks
7
+ `Fonts#glyph_width`, `Fonts#glyph_widths`, `Fonts#measure_text`, and
8
+ `Fonts#extract_ttf_widths` for all TrueType/OpenType fonts.
9
+
10
+ ## Bug description
11
+
12
+ In `extract_ttf_widths` (fonts.rb:380-400):
13
+
14
+ ```ruby
15
+ ttf = Pdfrb::Font::TrueType::File.new(data)
16
+ cmap = ttf.table("cmap") # Returns: String (raw bytes)
17
+ hmtx = ttf.table("hmtx") # Returns: String (raw bytes)
18
+
19
+ gid = cmap.glyph_id_for(cp) # ERROR: undefined method 'glyph_id_for' for String
20
+ ```
21
+
22
+ `ttf.table("cmap")` returns the raw binary data of the cmap table as
23
+ a String, not a parsed `CmapTable` object with a `glyph_id_for` method.
24
+
25
+ ## Reproduction
26
+
27
+ ```ruby
28
+ require "pdfrb"
29
+ doc = Pdfrb::Document.new
30
+ font = doc.fonts.add("/System/Library/Fonts/Supplemental/Arial.ttf")
31
+ doc.fonts.glyph_width(font, 65)
32
+ # => 0 (should be ~667 for 'A' in Arial)
33
+ # Warning: pdfrb: could not extract TTF widths: undefined method
34
+ # 'glyph_id_for' for an instance of String
35
+ ```
36
+
37
+ Standard 14 fonts (Helvetica, Times, Courier) work because they use
38
+ AFM data, not TTF parsing.
39
+
40
+ ## Impact
41
+
42
+ - `glyph_width` / `glyph_widths` return 0 for all TTF/OTF fonts.
43
+ - `measure_text` returns 0 for TTF/OTF text.
44
+ - `metrics_for` returns empty hash for TTF/OTF fonts.
45
+ - Font width arrays in FontDescriptor are empty or wrong.
46
+ - Font embedding (FontFile2) may have incorrect /Widths array.
47
+
48
+ This blocks the `idml` gem from:
49
+ - Using pdfrb's measurement API (TODO 63)
50
+ - Replacing Fontisan (the idml gem keeps fontisan as a fallback)
51
+ - Producing correct PDFs with embedded TrueType fonts
52
+
53
+ ## Proposed fix
54
+
55
+ `TrueType::File#table(name)` should return a parsed table object:
56
+
57
+ ```ruby
58
+ class Pdfrb::Font::TrueType::File
59
+ def table(name)
60
+ entry = @tables[name]
61
+ return nil unless entry
62
+
63
+ data = @data[entry.offset, entry.length]
64
+ parse_table(name, data)
65
+ end
66
+
67
+ def parse_table(name, data)
68
+ case name
69
+ when "cmap" then CmapTable.new(data)
70
+ when "hmtx" then HmtxTable.new(data, @num_hmetrics)
71
+ when "head" then HeadTable.new(data)
72
+ when "hhea" then HheaTable.new(data)
73
+ when "name" then NameTable.new(data)
74
+ else data # fallback: return raw bytes
75
+ end
76
+ end
77
+ end
78
+
79
+ class CmapTable
80
+ def initialize(data)
81
+ @data = data
82
+ @subtables = parse_subtables(data)
83
+ end
84
+
85
+ def glyph_id_for(codepoint)
86
+ @subtables.each do |sub|
87
+ gid = sub.lookup(codepoint)
88
+ return gid if gid && gid > 0
89
+ end
90
+ nil
91
+ end
92
+ end
93
+
94
+ class HmtxTable
95
+ def initialize(data, num_metrics)
96
+ @widths = []
97
+ num_metrics.times do |i|
98
+ @widths[i] = data[i * 4, 2].unpack1("n")
99
+ end
100
+ end
101
+
102
+ def width_for(glyph_id)
103
+ @widths[glyph_id] || @widths.last || 0
104
+ end
105
+ end
106
+ ```
107
+
108
+ ## Priority
109
+
110
+ **Critical** — this is the #1 bug blocking pdfrb adoption for the idml
111
+ gem. Without TTF parsing, glyph widths are wrong, text measurement
112
+ fails, and font embedding produces incorrect PDFs.
data/RELEASE.md ADDED
@@ -0,0 +1,61 @@
1
+ # Releasing pdfrb
2
+
3
+ Releases are driven by the Metanorma CI reusable workflow at
4
+ `.github/workflows/release.yml`. It supports two triggers:
5
+
6
+ 1. **`workflow_dispatch`** with a `next_version` input — manual run
7
+ from the Actions UI. Accepted values: `x.y.z`, `major`, `minor`,
8
+ `patch`, or `pre|rc|etc` to bump to a prerelease.
9
+ 2. **`repository_dispatch`** with event type `do-release` — for
10
+ automation triggers from other repos.
11
+
12
+ Both call
13
+ [`metanorma/ci/.github/workflows/rubygems-release.yml@main`](https://github.com/metanorma/ci/blob/main/.github/workflows/rubygems-release.yml),
14
+ which handles version bumping, tag creation, gem build, RubyGems
15
+ publish, and GitHub release creation.
16
+
17
+ ## Required secrets
18
+
19
+ * `CLARICLE_CI_RUBYGEMS_API_KEY` — RubyGems API key with `push`
20
+ permission on the `pdfrb` gem. Set in repo Settings → Secrets and
21
+ Variables → Actions.
22
+ * `GITHUB_TOKEN` — automatic; used for creating the GitHub release.
23
+
24
+ ## Triggering a release
25
+
26
+ ### From the Actions UI
27
+
28
+ 1. Go to Actions → `release` workflow.
29
+ 2. Click "Run workflow".
30
+ 3. Enter the next version (e.g., `0.7.0`, `patch`, `minor`, `major`).
31
+ 4. Click "Run workflow".
32
+
33
+ ### From the API / CI
34
+
35
+ ```sh
36
+ gh workflow run release.yml \
37
+ -f next_version=0.7.0
38
+ ```
39
+
40
+ Or via `repository_dispatch` from another repo:
41
+
42
+ ```sh
43
+ gh api /repos/claricle/pdfrb/dispatches \
44
+ -f event_type=do-release \
45
+ -f 'client_payload[next_version]=0.7.0'
46
+ ```
47
+
48
+ ## CI (test) workflow
49
+
50
+ `.github/workflows/rake.yml` runs the standard Metanorma CI
51
+ generic-rake workflow on every push to `main`/`master`, every tag
52
+ push, every pull request, and via manual `workflow_dispatch`. It
53
+ fires the test matrix across supported Ruby versions.
54
+
55
+ ## Pre-release checklist
56
+
57
+ * `bundle exec rake` is green locally.
58
+ * `lib/pdfrb/version.rb` matches the intended release (the release
59
+ workflow handles this automatically when given `next_version`).
60
+ * `CHANGELOG.md` has an entry for the new version.
61
+ * No uncommitted changes on `main`.