pdfrb 0.3.0 → 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 (404) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Gemfile +1 -0
  4. data/PROPOSAL.canvas-clip.md +92 -0
  5. data/PROPOSAL.canvas-draw-image-matrix.md +87 -0
  6. data/PROPOSAL.canvas-rich-text.md +103 -0
  7. data/PROPOSAL.canvas-text-lines.md +77 -0
  8. data/PROPOSAL.canvas-transparency.md +106 -0
  9. data/PROPOSAL.external-font-metrics.md +129 -0
  10. data/PROPOSAL.font-embedding-fontfile2.md +88 -0
  11. data/PROPOSAL.font-resolver-ttc.md +105 -0
  12. data/PROPOSAL.font-resolver.md +96 -0
  13. data/PROPOSAL.font-subsetting.md +98 -0
  14. data/PROPOSAL.gradient-shadings.md +110 -0
  15. data/PROPOSAL.page-mediabox-setter.md +66 -0
  16. data/PROPOSAL.per-glyph-width.md +91 -0
  17. data/PROPOSAL.stringio-require.md +53 -0
  18. data/PROPOSAL.struct-tree-root.md +102 -0
  19. data/PROPOSAL.text-measurement.md +93 -0
  20. data/PROPOSAL.ttf-table-parsing-fix.md +112 -0
  21. data/RELEASE.md +48 -0
  22. data/lib/pdfrb/action/base.rb +21 -0
  23. data/lib/pdfrb/action/types.rb +178 -0
  24. data/lib/pdfrb/action.rb +55 -0
  25. data/lib/pdfrb/annotation/base.rb +79 -0
  26. data/lib/pdfrb/annotation/types.rb +222 -0
  27. data/lib/pdfrb/annotation.rb +78 -0
  28. data/lib/pdfrb/appearance/generator.rb +216 -0
  29. data/lib/pdfrb/appearance.rb +11 -0
  30. data/lib/pdfrb/arlington/object_definition.rb +2 -2
  31. data/lib/pdfrb/arlington/predicate/evaluator.rb +1 -1
  32. data/lib/pdfrb/arlington/predicate/functions.rb +25 -9
  33. data/lib/pdfrb/arlington/predicate.rb +1 -5
  34. data/lib/pdfrb/cli/batch.rb +18 -0
  35. data/lib/pdfrb/cli/debug_info.rb +18 -0
  36. data/lib/pdfrb/cli/files.rb +16 -0
  37. data/lib/pdfrb/cli/fonts.rb +16 -0
  38. data/lib/pdfrb/cli/form.rb +18 -0
  39. data/lib/pdfrb/cli/image2pdf.rb +18 -0
  40. data/lib/pdfrb/cli/images.rb +34 -0
  41. data/lib/pdfrb/cli/info.rb +20 -0
  42. data/lib/pdfrb/cli/inspect.rb +18 -0
  43. data/lib/pdfrb/cli/merge.rb +18 -0
  44. data/lib/pdfrb/cli/modify.rb +18 -0
  45. data/lib/pdfrb/cli/optimize.rb +18 -0
  46. data/lib/pdfrb/cli/split.rb +21 -0
  47. data/lib/pdfrb/cli/watermark.rb +18 -0
  48. data/lib/pdfrb/cli.rb +291 -7
  49. data/lib/pdfrb/color/color_space.rb +259 -0
  50. data/lib/pdfrb/color/icc_profile.rb +90 -0
  51. data/lib/pdfrb/color.rb +12 -0
  52. data/lib/pdfrb/compare/comparator.rb +244 -0
  53. data/lib/pdfrb/compare/report.rb +78 -0
  54. data/lib/pdfrb/compare.rb +42 -0
  55. data/lib/pdfrb/composer.rb +161 -0
  56. data/lib/pdfrb/conformance/pdf_a.rb +317 -56
  57. data/lib/pdfrb/conformance/pdf_ua.rb +186 -29
  58. data/lib/pdfrb/conformance/pdf_x.rb +247 -0
  59. data/lib/pdfrb/conformance/rule.rb +78 -0
  60. data/lib/pdfrb/conformance/structure_elements.rb +174 -0
  61. data/lib/pdfrb/conformance/verapdf_bridge.rb +92 -0
  62. data/lib/pdfrb/conformance.rb +7 -3
  63. data/lib/pdfrb/content/canvas.rb +217 -72
  64. data/lib/pdfrb/content/color_space.rb +157 -0
  65. data/lib/pdfrb/content/hidden_text_detector.rb +167 -0
  66. data/lib/pdfrb/content/operator.rb +21 -1
  67. data/lib/pdfrb/content/operators/clipping.rb +36 -0
  68. data/lib/pdfrb/content/operators/graphics_state_params.rb +15 -0
  69. data/lib/pdfrb/content/operators.rb +21 -0
  70. data/lib/pdfrb/content/shading/base.rb +139 -0
  71. data/lib/pdfrb/content/shading.rb +17 -0
  72. data/lib/pdfrb/content/smart_text_extractor.rb +85 -0
  73. data/lib/pdfrb/content/tiling_pattern.rb +78 -0
  74. data/lib/pdfrb/content/transformation_matrix.rb +61 -0
  75. data/lib/pdfrb/content.rb +7 -26
  76. data/lib/pdfrb/destination/fit.rb +185 -0
  77. data/lib/pdfrb/destination.rb +13 -0
  78. data/lib/pdfrb/digital_signature/cms_handler.rb +22 -0
  79. data/lib/pdfrb/digital_signature/signing.rb +107 -11
  80. data/lib/pdfrb/digital_signature/timestamp_handler.rb +45 -0
  81. data/lib/pdfrb/digital_signature/verification.rb +88 -9
  82. data/lib/pdfrb/digital_signature/verification_result.rb +14 -0
  83. data/lib/pdfrb/digital_signature.rb +26 -2
  84. data/lib/pdfrb/document/annotations.rb +120 -3
  85. data/lib/pdfrb/document/associated_files.rb +104 -0
  86. data/lib/pdfrb/document/colors.rb +95 -0
  87. data/lib/pdfrb/document/destinations.rb +127 -5
  88. data/lib/pdfrb/document/display.rb +84 -0
  89. data/lib/pdfrb/document/fonts.rb +417 -45
  90. data/lib/pdfrb/document/form.rb +338 -0
  91. data/lib/pdfrb/document/graphics_state.rb +91 -0
  92. data/lib/pdfrb/document/images.rb +4 -4
  93. data/lib/pdfrb/document/info.rb +102 -0
  94. data/lib/pdfrb/document/layers.rb +62 -0
  95. data/lib/pdfrb/document/metadata.rb +12 -5
  96. data/lib/pdfrb/document/output_intents.rb +91 -0
  97. data/lib/pdfrb/document/page_labels.rb +80 -0
  98. data/lib/pdfrb/document/pages.rb +68 -19
  99. data/lib/pdfrb/document/portfolio.rb +119 -0
  100. data/lib/pdfrb/document/shadings.rb +159 -0
  101. data/lib/pdfrb/document/stamps.rb +68 -0
  102. data/lib/pdfrb/document/structure.rb +242 -0
  103. data/lib/pdfrb/document.rb +73 -4
  104. data/lib/pdfrb/encryption/identity.rb +13 -0
  105. data/lib/pdfrb/encryption/password_verification.rb +53 -8
  106. data/lib/pdfrb/encryption/security_handler.rb +8 -5
  107. data/lib/pdfrb/encryption/standard_security_handler.rb +154 -81
  108. data/lib/pdfrb/encryption.rb +17 -0
  109. data/lib/pdfrb/error.rb +2 -2
  110. data/lib/pdfrb/filter/brotli_decode.rb +32 -0
  111. data/lib/pdfrb/filter/ccitt_fax_decode.rb +12 -0
  112. data/lib/pdfrb/filter/crypt.rb +2 -2
  113. data/lib/pdfrb/filter/dct_decode.rb +18 -0
  114. data/lib/pdfrb/filter/flate_decode.rb +4 -18
  115. data/lib/pdfrb/filter/jbig2_decode.rb +12 -0
  116. data/lib/pdfrb/filter/jpx_decode.rb +18 -0
  117. data/lib/pdfrb/filter/lzw_decode.rb +3 -2
  118. data/lib/pdfrb/filter/png_predictor.rb +94 -0
  119. data/lib/pdfrb/filter.rb +26 -13
  120. data/lib/pdfrb/font/afm_parser.rb +50 -26
  121. data/lib/pdfrb/font/cmap/writer.rb +9 -0
  122. data/lib/pdfrb/font/encoding/win_ansi_encoding.rb +17 -0
  123. data/lib/pdfrb/font/encoding.rb +32 -3
  124. data/lib/pdfrb/font/metrics_helper.rb +121 -0
  125. data/lib/pdfrb/font/true_type/file.rb +10 -1
  126. data/lib/pdfrb/font/true_type/glyf.rb +82 -0
  127. data/lib/pdfrb/font/true_type/kern.rb +58 -0
  128. data/lib/pdfrb/font/true_type/loca.rb +42 -0
  129. data/lib/pdfrb/font/true_type/maxp.rb +44 -0
  130. data/lib/pdfrb/font/true_type/name.rb +53 -0
  131. data/lib/pdfrb/font/true_type/post.rb +93 -0
  132. data/lib/pdfrb/font/true_type/subsetter.rb +3 -5
  133. data/lib/pdfrb/font/true_type/wrapper.rb +102 -0
  134. data/lib/pdfrb/font/true_type.rb +7 -0
  135. data/lib/pdfrb/font.rb +2 -0
  136. data/lib/pdfrb/font_loader/from_configuration.rb +19 -0
  137. data/lib/pdfrb/font_loader/from_file.rb +20 -0
  138. data/lib/pdfrb/font_loader/standard14.rb +20 -0
  139. data/lib/pdfrb/font_loader/variant_from_name.rb +36 -0
  140. data/lib/pdfrb/font_loader.rb +4 -0
  141. data/lib/pdfrb/font_resolver.rb +138 -0
  142. data/lib/pdfrb/image/audit.rb +94 -0
  143. data/lib/pdfrb/image/downsampler.rb +124 -0
  144. data/lib/pdfrb/image.rb +13 -0
  145. data/lib/pdfrb/image_loader/jpeg.rb +39 -58
  146. data/lib/pdfrb/image_loader/png.rb +31 -257
  147. data/lib/pdfrb/layout/bidi.rb +198 -0
  148. data/lib/pdfrb/layout/box.rb +49 -0
  149. data/lib/pdfrb/layout/box_fitter.rb +54 -0
  150. data/lib/pdfrb/layout/column_box.rb +71 -0
  151. data/lib/pdfrb/layout/container_box.rb +45 -0
  152. data/lib/pdfrb/layout/frame.rb +67 -0
  153. data/lib/pdfrb/layout/image_box.rb +44 -0
  154. data/lib/pdfrb/layout/inline_box.rb +25 -0
  155. data/lib/pdfrb/layout/line.rb +55 -0
  156. data/lib/pdfrb/layout/list_box.rb +87 -0
  157. data/lib/pdfrb/layout/numeric_refinements.rb +43 -0
  158. data/lib/pdfrb/layout/page_style.rb +65 -0
  159. data/lib/pdfrb/layout/style.rb +62 -0
  160. data/lib/pdfrb/layout/table_box.rb +66 -0
  161. data/lib/pdfrb/layout/text_box.rb +38 -0
  162. data/lib/pdfrb/layout/text_fragment.rb +45 -0
  163. data/lib/pdfrb/layout/text_layouter.rb +123 -0
  164. data/lib/pdfrb/layout.rb +28 -0
  165. data/lib/pdfrb/linearization/hint_stream.rb +93 -0
  166. data/lib/pdfrb/linearization/writer.rb +259 -0
  167. data/lib/pdfrb/linearization.rb +21 -0
  168. data/lib/pdfrb/model/cos/dictionary.rb +12 -0
  169. data/lib/pdfrb/model/pdf_array.rb +2 -2
  170. data/lib/pdfrb/model/type/action.rb +42 -0
  171. data/lib/pdfrb/model/type/action_go_to_3d_view.rb +14 -0
  172. data/lib/pdfrb/model/type/action_go_to_dp.rb +16 -0
  173. data/lib/pdfrb/model/type/action_go_to_r.rb +26 -0
  174. data/lib/pdfrb/model/type/action_goto.rb +34 -0
  175. data/lib/pdfrb/model/type/action_hide.rb +26 -0
  176. data/lib/pdfrb/model/type/action_import_data.rb +18 -0
  177. data/lib/pdfrb/model/type/action_java_script.rb +18 -0
  178. data/lib/pdfrb/model/type/action_launch.rb +22 -0
  179. data/lib/pdfrb/model/type/action_movie.rb +22 -0
  180. data/lib/pdfrb/model/type/action_named.rb +23 -0
  181. data/lib/pdfrb/model/type/action_nop.rb +12 -0
  182. data/lib/pdfrb/model/type/action_rendition.rb +28 -0
  183. data/lib/pdfrb/model/type/action_reset_form.rb +22 -0
  184. data/lib/pdfrb/model/type/action_rich_media_execute.rb +17 -0
  185. data/lib/pdfrb/model/type/action_set_ocg_state.rb +32 -0
  186. data/lib/pdfrb/model/type/action_set_state.rb +14 -0
  187. data/lib/pdfrb/model/type/action_sound_action.rb +23 -0
  188. data/lib/pdfrb/model/type/action_submit_form.rb +64 -0
  189. data/lib/pdfrb/model/type/action_thread.rb +23 -0
  190. data/lib/pdfrb/model/type/action_trans.rb +30 -0
  191. data/lib/pdfrb/model/type/action_uri.rb +30 -0
  192. data/lib/pdfrb/model/type/af_embedded_file.rb +11 -0
  193. data/lib/pdfrb/model/type/af_file_specification.rb +34 -0
  194. data/lib/pdfrb/model/type/annotation.rb +49 -10
  195. data/lib/pdfrb/model/type/appearance.rb +41 -0
  196. data/lib/pdfrb/model/type/appearance_characteristics.rb +36 -0
  197. data/lib/pdfrb/model/type/appearance_generator.rb +22 -0
  198. data/lib/pdfrb/model/type/appearance_trap_net.rb +84 -0
  199. data/lib/pdfrb/model/type/border_effect.rb +25 -0
  200. data/lib/pdfrb/model/type/border_styling.rb +38 -0
  201. data/lib/pdfrb/model/type/box_color_info.rb +21 -0
  202. data/lib/pdfrb/model/type/box_style.rb +19 -0
  203. data/lib/pdfrb/model/type/button.rb +17 -0
  204. data/lib/pdfrb/model/type/cal_gray.rb +17 -0
  205. data/lib/pdfrb/model/type/cal_rgb.rb +22 -0
  206. data/lib/pdfrb/model/type/caret_annotation.rb +21 -0
  207. data/lib/pdfrb/model/type/catalog.rb +99 -16
  208. data/lib/pdfrb/model/type/choice.rb +21 -0
  209. data/lib/pdfrb/model/type/cid_font.rb +52 -1
  210. data/lib/pdfrb/model/type/cid_font_descriptor_metrics.rb +28 -0
  211. data/lib/pdfrb/model/type/cid_system_info.rb +28 -0
  212. data/lib/pdfrb/model/type/circle_annotation.rb +20 -0
  213. data/lib/pdfrb/model/type/collection.rb +27 -0
  214. data/lib/pdfrb/model/type/collection_field.rb +24 -0
  215. data/lib/pdfrb/model/type/collection_item.rb +19 -0
  216. data/lib/pdfrb/model/type/collection_schema.rb +25 -0
  217. data/lib/pdfrb/model/type/collection_sort.rb +13 -0
  218. data/lib/pdfrb/model/type/crypt_filter.rb +58 -0
  219. data/lib/pdfrb/model/type/device_n.rb +37 -0
  220. data/lib/pdfrb/model/type/device_n_mixing_hints.rb +17 -0
  221. data/lib/pdfrb/model/type/device_n_process.rb +13 -0
  222. data/lib/pdfrb/model/type/doc_mdp_transform_parameters.rb +21 -0
  223. data/lib/pdfrb/model/type/document_security_store.rb +55 -0
  224. data/lib/pdfrb/model/type/embedded_file.rb +19 -0
  225. data/lib/pdfrb/model/type/embedded_file_parameter.rb +48 -0
  226. data/lib/pdfrb/model/type/encryption_public_key.rb +38 -0
  227. data/lib/pdfrb/model/type/encryption_standard.rb +68 -0
  228. data/lib/pdfrb/model/type/field_mdp_transform_parameters.rb +26 -0
  229. data/lib/pdfrb/model/type/file_attachment_annotation.rb +29 -0
  230. data/lib/pdfrb/model/type/file_spec_ef.rb +22 -0
  231. data/lib/pdfrb/model/type/file_spec_rf.rb +21 -0
  232. data/lib/pdfrb/model/type/file_specification.rb +43 -0
  233. data/lib/pdfrb/model/type/file_trailer.rb +54 -0
  234. data/lib/pdfrb/model/type/font.rb +73 -2
  235. data/lib/pdfrb/model/type/font_cid_type0.rb +17 -0
  236. data/lib/pdfrb/model/type/font_cid_type2.rb +17 -0
  237. data/lib/pdfrb/model/type/font_descriptor.rb +47 -0
  238. data/lib/pdfrb/model/type/font_descriptor_cid_type0.rb +15 -0
  239. data/lib/pdfrb/model/type/font_descriptor_cid_type2.rb +15 -0
  240. data/lib/pdfrb/model/type/font_encoding.rb +47 -0
  241. data/lib/pdfrb/model/type/font_file.rb +28 -0
  242. data/lib/pdfrb/model/type/font_file2.rb +32 -0
  243. data/lib/pdfrb/model/type/font_file3.rb +23 -0
  244. data/lib/pdfrb/model/type/font_multiple_master.rb +60 -0
  245. data/lib/pdfrb/model/type/font_true_type.rb +1 -1
  246. data/lib/pdfrb/model/type/font_type0.rb +1 -1
  247. data/lib/pdfrb/model/type/font_type1.rb +1 -1
  248. data/lib/pdfrb/model/type/font_type3.rb +1 -1
  249. data/lib/pdfrb/model/type/form_field.rb +73 -0
  250. data/lib/pdfrb/model/type/free_text_annotation.rb +37 -0
  251. data/lib/pdfrb/model/type/function.rb +42 -0
  252. data/lib/pdfrb/model/type/function_exponential.rb +31 -0
  253. data/lib/pdfrb/model/type/function_postscript.rb +25 -0
  254. data/lib/pdfrb/model/type/function_sampled.rb +55 -0
  255. data/lib/pdfrb/model/type/function_stitching.rb +33 -0
  256. data/lib/pdfrb/model/type/generic_appearance.rb +40 -0
  257. data/lib/pdfrb/model/type/graphics_state_parameter.rb +69 -0
  258. data/lib/pdfrb/model/type/halftone.rb +21 -0
  259. data/lib/pdfrb/model/type/halftone_type1.rb +17 -0
  260. data/lib/pdfrb/model/type/halftone_type10.rb +16 -0
  261. data/lib/pdfrb/model/type/halftone_type16.rb +11 -0
  262. data/lib/pdfrb/model/type/halftone_type5.rb +24 -0
  263. data/lib/pdfrb/model/type/halftone_type6.rb +16 -0
  264. data/lib/pdfrb/model/type/highlight_annotation.rb +11 -0
  265. data/lib/pdfrb/model/type/icc_based_color_space.rb +24 -0
  266. data/lib/pdfrb/model/type/icon_fit.rb +31 -0
  267. data/lib/pdfrb/model/type/indexed.rb +32 -0
  268. data/lib/pdfrb/model/type/info.rb +44 -0
  269. data/lib/pdfrb/model/type/ink_annotation.rb +29 -0
  270. data/lib/pdfrb/model/type/interactive_form.rb +36 -0
  271. data/lib/pdfrb/model/type/interior_color.rb +12 -0
  272. data/lib/pdfrb/model/type/jbig2_globals.rb +15 -0
  273. data/lib/pdfrb/model/type/lab.rb +27 -0
  274. data/lib/pdfrb/model/type/line_annotation.rb +44 -0
  275. data/lib/pdfrb/model/type/line_ending_styling.rb +39 -0
  276. data/lib/pdfrb/model/type/link_annotation.rb +41 -0
  277. data/lib/pdfrb/model/type/link_appearance.rb +9 -0
  278. data/lib/pdfrb/model/type/mark_information.rb +23 -0
  279. data/lib/pdfrb/model/type/marked_content_reference.rb +24 -0
  280. data/lib/pdfrb/model/type/markup_annotation.rb +36 -0
  281. data/lib/pdfrb/model/type/mdp_dict.rb +28 -0
  282. data/lib/pdfrb/model/type/measure.rb +39 -0
  283. data/lib/pdfrb/model/type/media_clip.rb +28 -0
  284. data/lib/pdfrb/model/type/media_offset.rb +106 -0
  285. data/lib/pdfrb/model/type/metadata.rb +27 -3
  286. data/lib/pdfrb/model/type/misc_helpers.rb +75 -0
  287. data/lib/pdfrb/model/type/movie.rb +28 -0
  288. data/lib/pdfrb/model/type/names.rb +51 -0
  289. data/lib/pdfrb/model/type/namespace.rb +27 -0
  290. data/lib/pdfrb/model/type/object_reference.rb +31 -0
  291. data/lib/pdfrb/model/type/object_stream.rb +38 -0
  292. data/lib/pdfrb/model/type/opt_content_ext.rb +94 -0
  293. data/lib/pdfrb/model/type/opt_content_page_element.rb +18 -0
  294. data/lib/pdfrb/model/type/optional_content_config.rb +56 -0
  295. data/lib/pdfrb/model/type/optional_content_group.rb +35 -10
  296. data/lib/pdfrb/model/type/optional_content_membership.rb +36 -2
  297. data/lib/pdfrb/model/type/optional_content_properties.rb +16 -1
  298. data/lib/pdfrb/model/type/outline.rb +40 -6
  299. data/lib/pdfrb/model/type/outline_item.rb +45 -0
  300. data/lib/pdfrb/model/type/output_intent.rb +30 -0
  301. data/lib/pdfrb/model/type/page.rb +127 -0
  302. data/lib/pdfrb/model/type/page_label.rb +68 -0
  303. data/lib/pdfrb/model/type/page_tree_node.rb +51 -16
  304. data/lib/pdfrb/model/type/page_tree_node_root.rb +15 -0
  305. data/lib/pdfrb/model/type/pattern.rb +16 -0
  306. data/lib/pdfrb/model/type/pattern_shading.rb +25 -0
  307. data/lib/pdfrb/model/type/pattern_tiling.rb +25 -0
  308. data/lib/pdfrb/model/type/polygon_annotation.rb +29 -0
  309. data/lib/pdfrb/model/type/polygon_polyline.rb +14 -0
  310. data/lib/pdfrb/model/type/polyline_annotation.rb +29 -0
  311. data/lib/pdfrb/model/type/popup_annotation.rb +20 -0
  312. data/lib/pdfrb/model/type/printer_mark_annotation.rb +13 -0
  313. data/lib/pdfrb/model/type/redact_annotation.rb +28 -0
  314. data/lib/pdfrb/model/type/rendition.rb +31 -0
  315. data/lib/pdfrb/model/type/resources.rb +59 -14
  316. data/lib/pdfrb/model/type/rich_media_activation.rb +24 -0
  317. data/lib/pdfrb/model/type/rich_media_animation.rb +25 -0
  318. data/lib/pdfrb/model/type/rich_media_annotation.rb +18 -0
  319. data/lib/pdfrb/model/type/rich_media_command.rb +19 -0
  320. data/lib/pdfrb/model/type/rich_media_configuration.rb +32 -0
  321. data/lib/pdfrb/model/type/rich_media_content.rb +28 -0
  322. data/lib/pdfrb/model/type/rich_media_cue_point.rb +18 -0
  323. data/lib/pdfrb/model/type/rich_media_deactivation.rb +17 -0
  324. data/lib/pdfrb/model/type/rich_media_instance.rb +33 -0
  325. data/lib/pdfrb/model/type/rich_media_presentation.rb +29 -0
  326. data/lib/pdfrb/model/type/rich_media_settings.rb +33 -0
  327. data/lib/pdfrb/model/type/rich_media_window.rb +20 -0
  328. data/lib/pdfrb/model/type/screen_annotation.rb +19 -0
  329. data/lib/pdfrb/model/type/separation.rb +25 -0
  330. data/lib/pdfrb/model/type/sig_field_lock.rb +25 -0
  331. data/lib/pdfrb/model/type/sig_field_seed_value.rb +25 -0
  332. data/lib/pdfrb/model/type/signature.rb +65 -0
  333. data/lib/pdfrb/model/type/signature_build.rb +86 -0
  334. data/lib/pdfrb/model/type/signature_field.rb +17 -0
  335. data/lib/pdfrb/model/type/software_identifier.rb +19 -0
  336. data/lib/pdfrb/model/type/sound.rb +38 -0
  337. data/lib/pdfrb/model/type/sound_annotation.rb +21 -0
  338. data/lib/pdfrb/model/type/square_annotation.rb +24 -0
  339. data/lib/pdfrb/model/type/square_circle.rb +13 -0
  340. data/lib/pdfrb/model/type/squiggly_annotation.rb +11 -0
  341. data/lib/pdfrb/model/type/stamp_annotation.rb +19 -0
  342. data/lib/pdfrb/model/type/strikeout_annotation.rb +11 -0
  343. data/lib/pdfrb/model/type/struct_elem.rb +75 -0
  344. data/lib/pdfrb/model/type/struct_tree_root.rb +34 -0
  345. data/lib/pdfrb/model/type/structure_attributes.rb +44 -0
  346. data/lib/pdfrb/model/type/structure_element_kid.rb +33 -0
  347. data/lib/pdfrb/model/type/text_annotation.rb +25 -0
  348. data/lib/pdfrb/model/type/text_appearance.rb +9 -0
  349. data/lib/pdfrb/model/type/text_field.rb +21 -0
  350. data/lib/pdfrb/model/type/text_markup_annotation.rb +30 -0
  351. data/lib/pdfrb/model/type/three_d_activation.rb +32 -0
  352. data/lib/pdfrb/model/type/three_d_animation_style.rb +24 -0
  353. data/lib/pdfrb/model/type/three_d_background.rb +28 -0
  354. data/lib/pdfrb/model/type/three_d_cross_section.rb +25 -0
  355. data/lib/pdfrb/model/type/three_d_lighting_scheme.rb +26 -0
  356. data/lib/pdfrb/model/type/three_d_measure.rb +20 -0
  357. data/lib/pdfrb/model/type/three_d_measure_3dc.rb +23 -0
  358. data/lib/pdfrb/model/type/three_d_measure_ad3.rb +14 -0
  359. data/lib/pdfrb/model/type/three_d_measure_ld3.rb +14 -0
  360. data/lib/pdfrb/model/type/three_d_measure_pd3.rb +20 -0
  361. data/lib/pdfrb/model/type/three_d_measure_rd3.rb +14 -0
  362. data/lib/pdfrb/model/type/three_d_node.rb +37 -0
  363. data/lib/pdfrb/model/type/three_d_reference.rb +21 -0
  364. data/lib/pdfrb/model/type/three_d_render_mode.rb +34 -0
  365. data/lib/pdfrb/model/type/three_d_stream.rb +48 -0
  366. data/lib/pdfrb/model/type/three_d_units.rb +18 -0
  367. data/lib/pdfrb/model/type/three_d_view.rb +40 -0
  368. data/lib/pdfrb/model/type/to_unicode_cmap_stream.rb +23 -0
  369. data/lib/pdfrb/model/type/transition.rb +68 -0
  370. data/lib/pdfrb/model/type/underline_annotation.rb +11 -0
  371. data/lib/pdfrb/model/type/ur_transform_parameters.rb +33 -0
  372. data/lib/pdfrb/model/type/uri_dict.rb +18 -0
  373. data/lib/pdfrb/model/type/url_alias.rb +19 -0
  374. data/lib/pdfrb/model/type/variable_text_field.rb +47 -0
  375. data/lib/pdfrb/model/type/viewer_preferences.rb +42 -0
  376. data/lib/pdfrb/model/type/watermark_annotation.rb +13 -0
  377. data/lib/pdfrb/model/type/widget_annotation.rb +48 -0
  378. data/lib/pdfrb/model/type/widget_appearance.rb +9 -0
  379. data/lib/pdfrb/model/type/xobject_form.rb +41 -0
  380. data/lib/pdfrb/model/type/xobject_image.rb +56 -0
  381. data/lib/pdfrb/model/type/xref_stream.rb +37 -0
  382. data/lib/pdfrb/model/type.rb +286 -6
  383. data/lib/pdfrb/serializer.rb +2 -2
  384. data/lib/pdfrb/source/tokenizer.rb +0 -2
  385. data/lib/pdfrb/task/benchmark.rb +83 -0
  386. data/lib/pdfrb/task/extract_text.rb +1 -1
  387. data/lib/pdfrb/task/generate_corpus.rb +130 -0
  388. data/lib/pdfrb/task/memory_profile.rb +84 -0
  389. data/lib/pdfrb/task/optimize.rb +97 -7
  390. data/lib/pdfrb/task.rb +3 -3
  391. data/lib/pdfrb/test_utils.rb +112 -0
  392. data/lib/pdfrb/validator.rb +82 -0
  393. data/lib/pdfrb/version.rb +1 -1
  394. data/lib/pdfrb/writer.rb +117 -27
  395. data/lib/pdfrb/xmp/packet.rb +122 -0
  396. data/lib/pdfrb/xmp/schemas.rb +96 -0
  397. data/lib/pdfrb/xmp.rb +44 -0
  398. data/lib/pdfrb/xref_section.rb +2 -2
  399. data/lib/pdfrb.rb +24 -54
  400. data/pdfrb.gemspec +45 -0
  401. data/script/apply_fixes.sh +843 -0
  402. data/script/make_jpeg_fixture.rb +53 -0
  403. data/script/make_png_fixture.rb +25 -0
  404. metadata +311 -2
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # Refinements on Numeric to convert CSS-style units to PDF points.
6
+ #
7
+ # Usage:
8
+ # using Pdfrb::Layout::NumericRefinements
9
+ # 2.cm # => 56.6929...
10
+ # 1.inch # => 72.0
11
+ module NumericRefinements
12
+ PT_PER_INCH = 72.0
13
+ PT_PER_CM = PT_PER_INCH / 2.54
14
+ PT_PER_MM = PT_PER_CM / 10.0
15
+
16
+ refine Numeric do
17
+ def pt
18
+ to_f
19
+ end
20
+
21
+ def cm
22
+ to_f * PT_PER_CM
23
+ end
24
+
25
+ def mm
26
+ to_f * PT_PER_MM
27
+ end
28
+
29
+ def inch
30
+ to_f * PT_PER_INCH
31
+ end
32
+
33
+ alias inches inch
34
+
35
+ def pixel(dpi: 96.0)
36
+ to_f * (PT_PER_INCH / dpi)
37
+ end
38
+
39
+ alias px pixel
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # A named page template. A PageStyle knows:
6
+ # - page dimensions (size + orientation)
7
+ # - margin
8
+ # - the next page style (chains)
9
+ # - a block that draws page chrome (header/footer) each time a
10
+ # new page with this style is created.
11
+ class PageStyle
12
+ attr_reader :name, :page_size, :orientation, :margin, :next_style, :block
13
+
14
+ PAGE_SIZES = {
15
+ A4: [595.28, 841.89],
16
+ A3: [841.89, 1190.55],
17
+ A5: [419.53, 595.28],
18
+ Letter: [612.0, 792.0],
19
+ Legal: [612.0, 1008.0],
20
+ Tabloid: [792.0, 1224.0],
21
+ }.freeze
22
+
23
+ def initialize(name:, page_size: :A4, orientation: :portrait,
24
+ margin: 36, next_style: nil, &block)
25
+ @name = name
26
+ @page_size = page_size
27
+ @orientation = orientation
28
+ @margin = margin
29
+ @next_style = next_style || name
30
+ @block = block
31
+ end
32
+
33
+ def dimensions
34
+ base = PAGE_SIZES[@page_size] || [612.0, 792.0]
35
+ if @orientation == :landscape
36
+ [base[1], base[0]]
37
+ else
38
+ base
39
+ end
40
+ end
41
+
42
+ def width
43
+ dimensions[0]
44
+ end
45
+
46
+ def height
47
+ dimensions[1]
48
+ end
49
+
50
+ def frame
51
+ m = @margin.is_a?(Array) ? @margin : [@margin] * 4
52
+ Frame.new(
53
+ left: m[3],
54
+ bottom: m[2],
55
+ width: width - m[1] - m[3],
56
+ height: height - m[0] - m[2]
57
+ )
58
+ end
59
+
60
+ def draw_chrome(canvas)
61
+ @block&.call(canvas)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # Immutable typographic + visual style. Updating a property
6
+ # returns a new Style; the original is unchanged.
7
+ #
8
+ # Built-in presets (:base, :title, :heading1, :heading2, :heading3,
9
+ # :code, :caption) can be loaded via +Style.new(:heading1)+ or
10
+ # merged via +Style.new(base: :heading1, **overrides)+.
11
+ class Style
12
+ PROPERTIES = %i[
13
+ font_name font_size font_options fill_color stroke_color
14
+ fill_alpha stroke_alpha line_width line_spacing character_spacing
15
+ word_spacing text_align vertical_align text_rendering_mode
16
+ text_rise font_features text_decoration text_underline_color
17
+ subscript superscript border padding margin border_color
18
+ border_style border_radius background background_alpha
19
+ overlap_overflow_alpha position text_transform word_break
20
+ hyphenate language first_line_indent text_indent
21
+ ].freeze
22
+
23
+ PRESETS = {
24
+ base: { font_name: "Helvetica", font_size: 10, line_spacing: 1.2,
25
+ fill_color: [0, 0, 0] },
26
+ title: { font_name: "Helvetica-Bold", font_size: 24,
27
+ fill_color: [0, 0, 0] },
28
+ heading1: { font_name: "Helvetica-Bold", font_size: 20,
29
+ fill_color: [0, 0, 0] },
30
+ heading2: { font_name: "Helvetica-Bold", font_size: 16 },
31
+ heading3: { font_name: "Helvetica-BoldOblique", font_size: 14 },
32
+ code: { font_name: "Courier", font_size: 10 },
33
+ caption: { font_name: "Helvetica-Oblique", font_size: 9,
34
+ fill_color: [0.3, 0.3, 0.3] },
35
+ }.freeze
36
+
37
+ def initialize(name_or_base = nil, **opts)
38
+ base = if name_or_base.is_a?(Hash)
39
+ name_or_base
40
+ elsif name_or_base.is_a?(Symbol)
41
+ PRESETS[name_or_base] || {}
42
+ else
43
+ {}
44
+ end
45
+ @values = base.merge(opts).freeze
46
+ end
47
+
48
+ def update(**opts)
49
+ self.class.new(@values.merge(opts))
50
+ end
51
+ alias dup_with update
52
+
53
+ def to_h
54
+ @values.dup
55
+ end
56
+
57
+ PROPERTIES.each do |prop|
58
+ define_method(prop) { @values[prop] }
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # A table of cells. Each cell holds a Box. Column widths are auto
6
+ # unless specified; row heights computed from content.
7
+ class TableBox < Box
8
+ attr_reader :rows, :column_widths
9
+
10
+ def initialize(rows:, column_widths: nil, **)
11
+ super(**)
12
+ @rows = rows
13
+ @column_widths = column_widths
14
+ end
15
+
16
+ def fit?(available_width, available_height)
17
+ compute_column_widths(available_width)
18
+ remaining = available_height
19
+ @rows.each do |row|
20
+ row_heights = []
21
+ row.each_with_index do |cell, col|
22
+ cell_w = @column_widths[col]
23
+ cell.fit?(cell_w, remaining) or return false
24
+ row_heights << cell.height
25
+ end
26
+ row_h = row_heights.max || 0
27
+ remaining -= row_h
28
+ end
29
+ @width = available_width
30
+ @height = available_height - remaining
31
+ true
32
+ end
33
+
34
+ def draw_content(canvas, x, y)
35
+ offset_y = y
36
+ @rows.each do |row|
37
+ max_h = 0
38
+ offset_x = x
39
+ row.each_with_index do |cell, col|
40
+ cell.draw(canvas, offset_x, offset_y)
41
+ offset_x += @column_widths[col]
42
+ max_h = cell.height if cell.height > max_h
43
+ end
44
+ offset_y -= max_h
45
+ end
46
+ end
47
+
48
+ def empty?
49
+ @rows.empty?
50
+ end
51
+
52
+ private
53
+
54
+ def compute_column_widths(available_width)
55
+ return @column_widths = equal_widths(available_width) if @column_widths.nil?
56
+
57
+ @column_widths.map!(&:to_f)
58
+ end
59
+
60
+ def equal_widths(available_width)
61
+ col_count = @rows.first&.size || 1
62
+ Array.new(col_count, available_width / col_count)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # Renders a string of text with word-wrap into a region. Uses
6
+ # TextLayouter internally.
7
+ class TextBox < Box
8
+ attr_reader :text, :lines
9
+
10
+ def initialize(text:, **)
11
+ super(**)
12
+ @text = text.to_s
13
+ @lines = []
14
+ end
15
+
16
+ def fit?(available_width, available_height)
17
+ layouter = TextLayouter.new(@style)
18
+ @lines = layouter.layout(@text, available_width)
19
+ @width = available_width
20
+ @height = @lines.sum(&:height)
21
+ @height <= available_height
22
+ end
23
+
24
+ def draw_content(canvas, x, y)
25
+ offset_y = y - (@lines.first&.ascender || 0)
26
+ @lines.each do |line|
27
+ line.draw(canvas, x, offset_y, available_width: @width,
28
+ alignment: @style.text_align || :left)
29
+ offset_y -= line.height
30
+ end
31
+ end
32
+
33
+ def empty?
34
+ @text.empty?
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # A single fragment of styled text — one run of consecutive glyphs
6
+ # with the same Style. Pieces are [[glyph_id, x_offset, width], ...]
7
+ # in font units.
8
+ class TextFragment
9
+ attr_reader :pieces, :style, :width, :height, :y_min, :y_max
10
+
11
+ def initialize(pieces:, style:, width:, height:, y_min:, y_max:)
12
+ @pieces = pieces
13
+ @style = style
14
+ @width = width
15
+ @height = height
16
+ @y_min = y_min
17
+ @y_max = y_max
18
+ end
19
+
20
+ def ascender
21
+ @y_max
22
+ end
23
+
24
+ def descender
25
+ -@y_min
26
+ end
27
+
28
+ def draw(canvas, x, y)
29
+ canvas.save_graphics_state do
30
+ if @style.fill_color
31
+ canvas.fill_color(@style.fill_color)
32
+ end
33
+ canvas.text(@pieces.map(&:first).pack("U*"), at: [x, y],
34
+ font: font_name_for_canvas, size: @style.font_size)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def font_name_for_canvas
41
+ @style.font_name || :Helvetica
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ module Layout
5
+ # Breaks a string into Layout::Line instances that fit a given
6
+ # width. Uses real per-glyph widths from the font's AFM or hmtx
7
+ # table when available, falling back to a heuristic estimate.
8
+ class TextLayouter
9
+ attr_reader :style
10
+
11
+ def initialize(style)
12
+ @style = style
13
+ @metrics = lookup_metrics
14
+ end
15
+
16
+ # @param text [String] the text to lay out.
17
+ # @param width [Float] target line width in PDF units.
18
+ # @return [Array<Line>] lines, each fitting in +width+.
19
+ def layout(text, width)
20
+ reordered = reorder_for_layout(text.to_s)
21
+ clusters = reordered.grapheme_clusters
22
+ return [] if clusters.empty?
23
+
24
+ lines = []
25
+ current = []
26
+ current_width = 0.0
27
+ clusters.each do |cluster|
28
+ cw = cluster_width(cluster)
29
+ if current_width + cw > width && !current.empty?
30
+ lines << build_line(current)
31
+ current = []
32
+ current_width = 0.0
33
+ end
34
+ current << cluster
35
+ current_width += cw
36
+ end
37
+ lines << build_line(current) unless current.empty?
38
+ lines
39
+ end
40
+
41
+ private
42
+
43
+ def reorder_for_layout(text)
44
+ return text unless Pdfrb::Layout::Bidi.rtl?(text)
45
+
46
+ Pdfrb::Layout::Bidi.reorder(text)
47
+ rescue StandardError
48
+ text
49
+ end
50
+
51
+ def lookup_metrics
52
+ font_name = @style.font_name
53
+ Pdfrb::Font::MetricsHelper.metrics_for_standard14(font_name)
54
+ rescue StandardError
55
+ nil
56
+ end
57
+
58
+ def cluster_width(cluster)
59
+ size = @style.font_size || 10
60
+ upem = @metrics&.units_per_em || 1000
61
+
62
+ if @metrics
63
+ total = 0.0
64
+ cluster.each_codepoint do |cp|
65
+ width_in_font_units = glyph_width_in_font_units(cp)
66
+ total += width_in_font_units
67
+ end
68
+ total * size / upem
69
+ else
70
+ # Heuristic fallback when no AFM available.
71
+ size * cluster.length * 0.5
72
+ end
73
+ end
74
+
75
+ def glyph_width_in_font_units(codepoint)
76
+ # Map Unicode codepoint → glyph name → AFM width.
77
+ glyph_name = unicode_to_glyph_name(codepoint)
78
+ return 500 unless glyph_name && @metrics
79
+
80
+ afm = afm_for(@style.font_name)
81
+ return 500 unless afm
82
+
83
+ width = afm.width_for(glyph_name)
84
+ width.positive? ? width : 500
85
+ end
86
+
87
+ def unicode_to_glyph_name(codepoint)
88
+ table = begin
89
+ Pdfrb::Font::Encoding::WinAnsiEncoding::TABLE
90
+ rescue StandardError
91
+ nil
92
+ end
93
+ return nil unless table
94
+
95
+ table[codepoint]
96
+ end
97
+
98
+ def afm_for(font_name)
99
+ @afm_cache ||= {}
100
+ return @afm_cache[font_name] if @afm_cache.key?(font_name)
101
+
102
+ @afm_cache[font_name] = Pdfrb::Font::MetricsHelper.afm_for(font_name.to_s)
103
+ end
104
+
105
+ def build_line(clusters)
106
+ pieces = clusters.map.with_index { |c, i| [c.ord, i, cluster_width(c)] }
107
+ size = @style.font_size || 10
108
+ ascender = @metrics ? @metrics.ascender(size) : size
109
+ descender = @metrics ? @metrics.descender(size) : -size * 0.2
110
+ Line.new(fragments: [
111
+ TextFragment.new(
112
+ pieces: pieces,
113
+ style: @style,
114
+ width: pieces.sum { |p| p[2] },
115
+ height: ascender - descender,
116
+ y_min: descender,
117
+ y_max: ascender
118
+ ),
119
+ ])
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pdfrb
4
+ # Layout engine (mirrors HexaPDF::Layout). High-level document
5
+ # composition: Frame + Box + Composer. Boxes (text, image, table,
6
+ # list) are placed into Frames which represent page regions. Content
7
+ # flows across pages when a Frame fills up.
8
+ module Layout
9
+ autoload :Frame, "pdfrb/layout/frame"
10
+ autoload :Style, "pdfrb/layout/style"
11
+ autoload :NumericRefinements, "pdfrb/layout/numeric_refinements"
12
+ autoload :Box, "pdfrb/layout/box"
13
+ autoload :ContainerBox, "pdfrb/layout/container_box"
14
+ autoload :TextBox, "pdfrb/layout/text_box"
15
+ autoload :ImageBox, "pdfrb/layout/image_box"
16
+ autoload :ListBox, "pdfrb/layout/list_box"
17
+ autoload :TableBox, "pdfrb/layout/table_box"
18
+ autoload :ColumnBox, "pdfrb/layout/column_box"
19
+ autoload :InlineBox, "pdfrb/layout/inline_box"
20
+ autoload :BoxFitter, "pdfrb/layout/box_fitter"
21
+ autoload :PageStyle, "pdfrb/layout/page_style"
22
+ autoload :TextLayouter, "pdfrb/layout/text_layouter"
23
+ autoload :TextFragment, "pdfrb/layout/text_fragment"
24
+ autoload :Line, "pdfrb/layout/line"
25
+ autoload :Bidi, "pdfrb/layout/bidi"
26
+ autoload :RomanNumeral, "pdfrb/layout/list_box"
27
+ end
28
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+ require "zlib"
5
+
6
+ module Pdfrb
7
+ module Linearization
8
+ # Builds the page-offset hint stream (ISO 32000-2 Annex F).
9
+ # The hint stream tells the viewer where each page's objects are
10
+ # located without needing to parse the full xref.
11
+ #
12
+ # This implementation produces a minimal valid hint table:
13
+ # /S 16 (16 bits per entry field)
14
+ # One page-offset entry per page.
15
+ class HintStream
16
+ DEFAULT_ITEM_BITS = 16
17
+
18
+ attr_reader :page_entries, :item_bits
19
+
20
+ def initialize(item_bits: DEFAULT_ITEM_BITS)
21
+ @item_bits = item_bits
22
+ @page_entries = []
23
+ end
24
+
25
+ # Add a page entry.
26
+ # @param offset_delta [Integer] offset relative to /O reference.
27
+ # @param page_length [Integer] length in bytes.
28
+ # @param num_objects [Integer] number of objects on this page.
29
+ # @param page_obj_num [Integer] object number of the Page dict.
30
+ def add_page(offset_delta:, page_length:, num_objects:, page_obj_num:)
31
+ @page_entries << {
32
+ offset_delta: offset_delta,
33
+ page_length: page_length,
34
+ num_objects: num_objects,
35
+ page_obj_num: page_obj_num,
36
+ }
37
+ end
38
+
39
+ # Encode the hint stream as PDF bytes (binary, ready for /Length).
40
+ # @return [String] binary hint table data.
41
+ def encode
42
+ bits = []
43
+
44
+ @page_entries.each do |entry|
45
+ bits << [entry[:offset_delta], @item_bits]
46
+ bits << [entry[:page_length], @item_bits]
47
+ bits << [entry[:num_objects], @item_bits]
48
+ bits << [entry[:page_obj_num], @item_bits]
49
+ end
50
+
51
+ packed = pack_bits(bits)
52
+ packed.force_encoding(Encoding::BINARY)
53
+ end
54
+
55
+ # Dictionary fields for the hint stream object.
56
+ def dictionary_fields(length)
57
+ {
58
+ S: @item_bits,
59
+ }.tap do |h|
60
+ h[:Length] = length
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def pack_bits(bit_fields)
67
+ bytes = +""
68
+ buffer = 0
69
+ bits_in_buffer = 0
70
+
71
+ bit_fields.each do |value, width|
72
+ width.times do |i|
73
+ bit = (value >> (width - 1 - i)) & 1
74
+ buffer = (buffer << 1) | bit
75
+ bits_in_buffer += 1
76
+ if bits_in_buffer == 8
77
+ bytes << [buffer].pack("C")
78
+ buffer = 0
79
+ bits_in_buffer = 0
80
+ end
81
+ end
82
+ end
83
+
84
+ if bits_in_buffer.positive?
85
+ buffer <<= (8 - bits_in_buffer)
86
+ bytes << [buffer].pack("C")
87
+ end
88
+
89
+ bytes
90
+ end
91
+ end
92
+ end
93
+ end