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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +24 -0
- data/Gemfile +1 -0
- data/PROPOSAL.canvas-clip.md +92 -0
- data/PROPOSAL.canvas-draw-image-matrix.md +87 -0
- data/PROPOSAL.canvas-rich-text.md +103 -0
- data/PROPOSAL.canvas-text-lines.md +77 -0
- data/PROPOSAL.canvas-transparency.md +106 -0
- data/PROPOSAL.external-font-metrics.md +129 -0
- data/PROPOSAL.font-embedding-fontfile2.md +88 -0
- data/PROPOSAL.font-resolver-ttc.md +105 -0
- data/PROPOSAL.font-resolver.md +96 -0
- data/PROPOSAL.font-subsetting.md +98 -0
- data/PROPOSAL.gradient-shadings.md +110 -0
- data/PROPOSAL.page-mediabox-setter.md +66 -0
- data/PROPOSAL.per-glyph-width.md +91 -0
- data/PROPOSAL.stringio-require.md +53 -0
- data/PROPOSAL.struct-tree-root.md +102 -0
- data/PROPOSAL.text-measurement.md +93 -0
- data/PROPOSAL.ttf-table-parsing-fix.md +112 -0
- data/RELEASE.md +48 -0
- data/lib/pdfrb/action/base.rb +21 -0
- data/lib/pdfrb/action/types.rb +178 -0
- data/lib/pdfrb/action.rb +55 -0
- data/lib/pdfrb/annotation/base.rb +79 -0
- data/lib/pdfrb/annotation/types.rb +222 -0
- data/lib/pdfrb/annotation.rb +78 -0
- data/lib/pdfrb/appearance/generator.rb +216 -0
- data/lib/pdfrb/appearance.rb +11 -0
- data/lib/pdfrb/arlington/object_definition.rb +2 -2
- data/lib/pdfrb/arlington/predicate/evaluator.rb +1 -1
- data/lib/pdfrb/arlington/predicate/functions.rb +25 -9
- data/lib/pdfrb/arlington/predicate.rb +1 -5
- data/lib/pdfrb/cli/batch.rb +18 -0
- data/lib/pdfrb/cli/debug_info.rb +18 -0
- data/lib/pdfrb/cli/files.rb +16 -0
- data/lib/pdfrb/cli/fonts.rb +16 -0
- data/lib/pdfrb/cli/form.rb +18 -0
- data/lib/pdfrb/cli/image2pdf.rb +18 -0
- data/lib/pdfrb/cli/images.rb +34 -0
- data/lib/pdfrb/cli/info.rb +20 -0
- data/lib/pdfrb/cli/inspect.rb +18 -0
- data/lib/pdfrb/cli/merge.rb +18 -0
- data/lib/pdfrb/cli/modify.rb +18 -0
- data/lib/pdfrb/cli/optimize.rb +18 -0
- data/lib/pdfrb/cli/split.rb +21 -0
- data/lib/pdfrb/cli/watermark.rb +18 -0
- data/lib/pdfrb/cli.rb +312 -7
- data/lib/pdfrb/color/color_space.rb +259 -0
- data/lib/pdfrb/color/icc_profile.rb +90 -0
- data/lib/pdfrb/color.rb +12 -0
- data/lib/pdfrb/compare/comparator.rb +244 -0
- data/lib/pdfrb/compare/report.rb +78 -0
- data/lib/pdfrb/compare.rb +42 -0
- data/lib/pdfrb/composer.rb +161 -0
- data/lib/pdfrb/conformance/pdf_a.rb +317 -56
- data/lib/pdfrb/conformance/pdf_ua.rb +186 -29
- data/lib/pdfrb/conformance/pdf_x.rb +247 -0
- data/lib/pdfrb/conformance/rule.rb +78 -0
- data/lib/pdfrb/conformance/structure_elements.rb +174 -0
- data/lib/pdfrb/conformance/verapdf_bridge.rb +92 -0
- data/lib/pdfrb/conformance.rb +7 -3
- data/lib/pdfrb/content/canvas.rb +217 -72
- data/lib/pdfrb/content/color_space.rb +157 -0
- data/lib/pdfrb/content/hidden_text_detector.rb +167 -0
- data/lib/pdfrb/content/operator.rb +21 -1
- data/lib/pdfrb/content/operators/clipping.rb +36 -0
- data/lib/pdfrb/content/operators/graphics_state_params.rb +15 -0
- data/lib/pdfrb/content/operators.rb +21 -0
- data/lib/pdfrb/content/shading/base.rb +139 -0
- data/lib/pdfrb/content/shading.rb +17 -0
- data/lib/pdfrb/content/smart_text_extractor.rb +85 -0
- data/lib/pdfrb/content/tiling_pattern.rb +78 -0
- data/lib/pdfrb/content/transformation_matrix.rb +61 -0
- data/lib/pdfrb/content.rb +7 -26
- data/lib/pdfrb/destination/fit.rb +185 -0
- data/lib/pdfrb/destination.rb +13 -0
- data/lib/pdfrb/digital_signature/cms_handler.rb +22 -0
- data/lib/pdfrb/digital_signature/signing.rb +107 -11
- data/lib/pdfrb/digital_signature/timestamp_handler.rb +45 -0
- data/lib/pdfrb/digital_signature/verification.rb +88 -9
- data/lib/pdfrb/digital_signature/verification_result.rb +14 -0
- data/lib/pdfrb/digital_signature.rb +26 -2
- data/lib/pdfrb/document/annotations.rb +120 -3
- data/lib/pdfrb/document/associated_files.rb +104 -0
- data/lib/pdfrb/document/colors.rb +95 -0
- data/lib/pdfrb/document/destinations.rb +127 -5
- data/lib/pdfrb/document/display.rb +84 -0
- data/lib/pdfrb/document/fonts.rb +417 -45
- data/lib/pdfrb/document/form.rb +338 -0
- data/lib/pdfrb/document/form_xobject.rb +68 -0
- data/lib/pdfrb/document/graphics_state.rb +91 -0
- data/lib/pdfrb/document/images.rb +4 -4
- data/lib/pdfrb/document/info.rb +102 -0
- data/lib/pdfrb/document/layers.rb +62 -0
- data/lib/pdfrb/document/metadata.rb +12 -5
- data/lib/pdfrb/document/output_intents.rb +91 -0
- data/lib/pdfrb/document/page_labels.rb +80 -0
- data/lib/pdfrb/document/pages.rb +68 -19
- data/lib/pdfrb/document/portfolio.rb +119 -0
- data/lib/pdfrb/document/shadings.rb +159 -0
- data/lib/pdfrb/document/stamps.rb +68 -0
- data/lib/pdfrb/document/structure.rb +242 -0
- data/lib/pdfrb/document.rb +73 -4
- data/lib/pdfrb/encryption/identity.rb +13 -0
- data/lib/pdfrb/encryption/password_verification.rb +53 -8
- data/lib/pdfrb/encryption/security_handler.rb +8 -5
- data/lib/pdfrb/encryption/standard_security_handler.rb +154 -81
- data/lib/pdfrb/encryption.rb +17 -0
- data/lib/pdfrb/error.rb +2 -2
- data/lib/pdfrb/filter/brotli_decode.rb +32 -0
- data/lib/pdfrb/filter/ccitt_fax_decode.rb +12 -0
- data/lib/pdfrb/filter/crypt.rb +2 -2
- data/lib/pdfrb/filter/dct_decode.rb +18 -0
- data/lib/pdfrb/filter/flate_decode.rb +4 -18
- data/lib/pdfrb/filter/jbig2_decode.rb +12 -0
- data/lib/pdfrb/filter/jpx_decode.rb +18 -0
- data/lib/pdfrb/filter/lzw_decode.rb +3 -2
- data/lib/pdfrb/filter/png_predictor.rb +94 -0
- data/lib/pdfrb/filter.rb +26 -13
- data/lib/pdfrb/font/afm_parser.rb +50 -26
- data/lib/pdfrb/font/cmap/writer.rb +9 -0
- data/lib/pdfrb/font/encoding/win_ansi_encoding.rb +17 -0
- data/lib/pdfrb/font/encoding.rb +32 -3
- data/lib/pdfrb/font/metrics_helper.rb +121 -0
- data/lib/pdfrb/font/true_type/file.rb +10 -1
- data/lib/pdfrb/font/true_type/glyf.rb +82 -0
- data/lib/pdfrb/font/true_type/kern.rb +58 -0
- data/lib/pdfrb/font/true_type/loca.rb +42 -0
- data/lib/pdfrb/font/true_type/maxp.rb +44 -0
- data/lib/pdfrb/font/true_type/name.rb +53 -0
- data/lib/pdfrb/font/true_type/post.rb +93 -0
- data/lib/pdfrb/font/true_type/subsetter.rb +3 -5
- data/lib/pdfrb/font/true_type/wrapper.rb +102 -0
- data/lib/pdfrb/font/true_type.rb +7 -0
- data/lib/pdfrb/font.rb +2 -0
- data/lib/pdfrb/font_loader/from_configuration.rb +19 -0
- data/lib/pdfrb/font_loader/from_file.rb +20 -0
- data/lib/pdfrb/font_loader/standard14.rb +20 -0
- data/lib/pdfrb/font_loader/variant_from_name.rb +36 -0
- data/lib/pdfrb/font_loader.rb +4 -0
- data/lib/pdfrb/font_resolver.rb +138 -0
- data/lib/pdfrb/image/audit.rb +94 -0
- data/lib/pdfrb/image/downsampler.rb +124 -0
- data/lib/pdfrb/image.rb +13 -0
- data/lib/pdfrb/image_loader/jpeg.rb +39 -58
- data/lib/pdfrb/image_loader/png.rb +31 -257
- data/lib/pdfrb/layout/bidi.rb +198 -0
- data/lib/pdfrb/layout/box.rb +49 -0
- data/lib/pdfrb/layout/box_fitter.rb +54 -0
- data/lib/pdfrb/layout/column_box.rb +71 -0
- data/lib/pdfrb/layout/container_box.rb +45 -0
- data/lib/pdfrb/layout/frame.rb +67 -0
- data/lib/pdfrb/layout/image_box.rb +44 -0
- data/lib/pdfrb/layout/inline_box.rb +25 -0
- data/lib/pdfrb/layout/line.rb +55 -0
- data/lib/pdfrb/layout/list_box.rb +87 -0
- data/lib/pdfrb/layout/numeric_refinements.rb +43 -0
- data/lib/pdfrb/layout/page_style.rb +65 -0
- data/lib/pdfrb/layout/style.rb +62 -0
- data/lib/pdfrb/layout/table_box.rb +66 -0
- data/lib/pdfrb/layout/text_box.rb +38 -0
- data/lib/pdfrb/layout/text_fragment.rb +45 -0
- data/lib/pdfrb/layout/text_layouter.rb +123 -0
- data/lib/pdfrb/layout.rb +28 -0
- data/lib/pdfrb/linearization/hint_stream.rb +93 -0
- data/lib/pdfrb/linearization/writer.rb +259 -0
- data/lib/pdfrb/linearization.rb +21 -0
- data/lib/pdfrb/model/cos/dictionary.rb +12 -0
- data/lib/pdfrb/model/pdf_array.rb +2 -2
- data/lib/pdfrb/model/type/action.rb +42 -0
- data/lib/pdfrb/model/type/action_go_to_3d_view.rb +14 -0
- data/lib/pdfrb/model/type/action_go_to_dp.rb +16 -0
- data/lib/pdfrb/model/type/action_go_to_r.rb +26 -0
- data/lib/pdfrb/model/type/action_goto.rb +34 -0
- data/lib/pdfrb/model/type/action_hide.rb +26 -0
- data/lib/pdfrb/model/type/action_import_data.rb +18 -0
- data/lib/pdfrb/model/type/action_java_script.rb +18 -0
- data/lib/pdfrb/model/type/action_launch.rb +22 -0
- data/lib/pdfrb/model/type/action_movie.rb +22 -0
- data/lib/pdfrb/model/type/action_named.rb +23 -0
- data/lib/pdfrb/model/type/action_nop.rb +12 -0
- data/lib/pdfrb/model/type/action_rendition.rb +28 -0
- data/lib/pdfrb/model/type/action_reset_form.rb +22 -0
- data/lib/pdfrb/model/type/action_rich_media_execute.rb +17 -0
- data/lib/pdfrb/model/type/action_set_ocg_state.rb +32 -0
- data/lib/pdfrb/model/type/action_set_state.rb +14 -0
- data/lib/pdfrb/model/type/action_sound_action.rb +23 -0
- data/lib/pdfrb/model/type/action_submit_form.rb +64 -0
- data/lib/pdfrb/model/type/action_thread.rb +23 -0
- data/lib/pdfrb/model/type/action_trans.rb +30 -0
- data/lib/pdfrb/model/type/action_uri.rb +30 -0
- data/lib/pdfrb/model/type/af_embedded_file.rb +11 -0
- data/lib/pdfrb/model/type/af_file_specification.rb +34 -0
- data/lib/pdfrb/model/type/annotation.rb +49 -10
- data/lib/pdfrb/model/type/appearance.rb +41 -0
- data/lib/pdfrb/model/type/appearance_characteristics.rb +36 -0
- data/lib/pdfrb/model/type/appearance_generator.rb +22 -0
- data/lib/pdfrb/model/type/appearance_trap_net.rb +84 -0
- data/lib/pdfrb/model/type/border_effect.rb +25 -0
- data/lib/pdfrb/model/type/border_styling.rb +38 -0
- data/lib/pdfrb/model/type/box_color_info.rb +21 -0
- data/lib/pdfrb/model/type/box_style.rb +19 -0
- data/lib/pdfrb/model/type/button.rb +17 -0
- data/lib/pdfrb/model/type/cal_gray.rb +17 -0
- data/lib/pdfrb/model/type/cal_rgb.rb +22 -0
- data/lib/pdfrb/model/type/caret_annotation.rb +21 -0
- data/lib/pdfrb/model/type/catalog.rb +99 -16
- data/lib/pdfrb/model/type/choice.rb +21 -0
- data/lib/pdfrb/model/type/cid_font.rb +52 -1
- data/lib/pdfrb/model/type/cid_font_descriptor_metrics.rb +28 -0
- data/lib/pdfrb/model/type/cid_system_info.rb +28 -0
- data/lib/pdfrb/model/type/circle_annotation.rb +20 -0
- data/lib/pdfrb/model/type/collection.rb +27 -0
- data/lib/pdfrb/model/type/collection_field.rb +24 -0
- data/lib/pdfrb/model/type/collection_item.rb +19 -0
- data/lib/pdfrb/model/type/collection_schema.rb +25 -0
- data/lib/pdfrb/model/type/collection_sort.rb +13 -0
- data/lib/pdfrb/model/type/crypt_filter.rb +58 -0
- data/lib/pdfrb/model/type/device_n.rb +37 -0
- data/lib/pdfrb/model/type/device_n_mixing_hints.rb +17 -0
- data/lib/pdfrb/model/type/device_n_process.rb +13 -0
- data/lib/pdfrb/model/type/doc_mdp_transform_parameters.rb +21 -0
- data/lib/pdfrb/model/type/document_security_store.rb +55 -0
- data/lib/pdfrb/model/type/embedded_file.rb +19 -0
- data/lib/pdfrb/model/type/embedded_file_parameter.rb +48 -0
- data/lib/pdfrb/model/type/encryption_public_key.rb +38 -0
- data/lib/pdfrb/model/type/encryption_standard.rb +68 -0
- data/lib/pdfrb/model/type/field_mdp_transform_parameters.rb +26 -0
- data/lib/pdfrb/model/type/file_attachment_annotation.rb +29 -0
- data/lib/pdfrb/model/type/file_spec_ef.rb +22 -0
- data/lib/pdfrb/model/type/file_spec_rf.rb +21 -0
- data/lib/pdfrb/model/type/file_specification.rb +43 -0
- data/lib/pdfrb/model/type/file_trailer.rb +54 -0
- data/lib/pdfrb/model/type/font.rb +73 -2
- data/lib/pdfrb/model/type/font_cid_type0.rb +17 -0
- data/lib/pdfrb/model/type/font_cid_type2.rb +17 -0
- data/lib/pdfrb/model/type/font_descriptor.rb +47 -0
- data/lib/pdfrb/model/type/font_descriptor_cid_type0.rb +15 -0
- data/lib/pdfrb/model/type/font_descriptor_cid_type2.rb +15 -0
- data/lib/pdfrb/model/type/font_encoding.rb +47 -0
- data/lib/pdfrb/model/type/font_file.rb +28 -0
- data/lib/pdfrb/model/type/font_file2.rb +32 -0
- data/lib/pdfrb/model/type/font_file3.rb +23 -0
- data/lib/pdfrb/model/type/font_multiple_master.rb +60 -0
- data/lib/pdfrb/model/type/font_true_type.rb +1 -1
- data/lib/pdfrb/model/type/font_type0.rb +1 -1
- data/lib/pdfrb/model/type/font_type1.rb +1 -1
- data/lib/pdfrb/model/type/font_type3.rb +1 -1
- data/lib/pdfrb/model/type/form_field.rb +73 -0
- data/lib/pdfrb/model/type/free_text_annotation.rb +37 -0
- data/lib/pdfrb/model/type/function.rb +42 -0
- data/lib/pdfrb/model/type/function_exponential.rb +31 -0
- data/lib/pdfrb/model/type/function_postscript.rb +25 -0
- data/lib/pdfrb/model/type/function_sampled.rb +55 -0
- data/lib/pdfrb/model/type/function_stitching.rb +33 -0
- data/lib/pdfrb/model/type/generic_appearance.rb +40 -0
- data/lib/pdfrb/model/type/graphics_state_parameter.rb +69 -0
- data/lib/pdfrb/model/type/halftone.rb +21 -0
- data/lib/pdfrb/model/type/halftone_type1.rb +17 -0
- data/lib/pdfrb/model/type/halftone_type10.rb +16 -0
- data/lib/pdfrb/model/type/halftone_type16.rb +11 -0
- data/lib/pdfrb/model/type/halftone_type5.rb +24 -0
- data/lib/pdfrb/model/type/halftone_type6.rb +16 -0
- data/lib/pdfrb/model/type/highlight_annotation.rb +11 -0
- data/lib/pdfrb/model/type/icc_based_color_space.rb +24 -0
- data/lib/pdfrb/model/type/icon_fit.rb +31 -0
- data/lib/pdfrb/model/type/indexed.rb +32 -0
- data/lib/pdfrb/model/type/info.rb +44 -0
- data/lib/pdfrb/model/type/ink_annotation.rb +29 -0
- data/lib/pdfrb/model/type/interactive_form.rb +36 -0
- data/lib/pdfrb/model/type/interior_color.rb +12 -0
- data/lib/pdfrb/model/type/jbig2_globals.rb +15 -0
- data/lib/pdfrb/model/type/lab.rb +27 -0
- data/lib/pdfrb/model/type/line_annotation.rb +44 -0
- data/lib/pdfrb/model/type/line_ending_styling.rb +39 -0
- data/lib/pdfrb/model/type/link_annotation.rb +41 -0
- data/lib/pdfrb/model/type/link_appearance.rb +9 -0
- data/lib/pdfrb/model/type/mark_information.rb +23 -0
- data/lib/pdfrb/model/type/marked_content_reference.rb +24 -0
- data/lib/pdfrb/model/type/markup_annotation.rb +36 -0
- data/lib/pdfrb/model/type/mdp_dict.rb +28 -0
- data/lib/pdfrb/model/type/measure.rb +39 -0
- data/lib/pdfrb/model/type/media_clip.rb +28 -0
- data/lib/pdfrb/model/type/media_offset.rb +106 -0
- data/lib/pdfrb/model/type/metadata.rb +27 -3
- data/lib/pdfrb/model/type/misc_helpers.rb +75 -0
- data/lib/pdfrb/model/type/movie.rb +28 -0
- data/lib/pdfrb/model/type/names.rb +51 -0
- data/lib/pdfrb/model/type/namespace.rb +27 -0
- data/lib/pdfrb/model/type/object_reference.rb +31 -0
- data/lib/pdfrb/model/type/object_stream.rb +38 -0
- data/lib/pdfrb/model/type/opt_content_ext.rb +94 -0
- data/lib/pdfrb/model/type/opt_content_page_element.rb +18 -0
- data/lib/pdfrb/model/type/optional_content_config.rb +56 -0
- data/lib/pdfrb/model/type/optional_content_group.rb +35 -10
- data/lib/pdfrb/model/type/optional_content_membership.rb +36 -2
- data/lib/pdfrb/model/type/optional_content_properties.rb +16 -1
- data/lib/pdfrb/model/type/outline.rb +40 -6
- data/lib/pdfrb/model/type/outline_item.rb +45 -0
- data/lib/pdfrb/model/type/output_intent.rb +30 -0
- data/lib/pdfrb/model/type/page.rb +127 -0
- data/lib/pdfrb/model/type/page_label.rb +68 -0
- data/lib/pdfrb/model/type/page_tree_node.rb +51 -16
- data/lib/pdfrb/model/type/page_tree_node_root.rb +15 -0
- data/lib/pdfrb/model/type/pattern.rb +16 -0
- data/lib/pdfrb/model/type/pattern_shading.rb +25 -0
- data/lib/pdfrb/model/type/pattern_tiling.rb +25 -0
- data/lib/pdfrb/model/type/polygon_annotation.rb +29 -0
- data/lib/pdfrb/model/type/polygon_polyline.rb +14 -0
- data/lib/pdfrb/model/type/polyline_annotation.rb +29 -0
- data/lib/pdfrb/model/type/popup_annotation.rb +20 -0
- data/lib/pdfrb/model/type/printer_mark_annotation.rb +13 -0
- data/lib/pdfrb/model/type/redact_annotation.rb +28 -0
- data/lib/pdfrb/model/type/rendition.rb +31 -0
- data/lib/pdfrb/model/type/resources.rb +59 -14
- data/lib/pdfrb/model/type/rich_media_activation.rb +24 -0
- data/lib/pdfrb/model/type/rich_media_animation.rb +25 -0
- data/lib/pdfrb/model/type/rich_media_annotation.rb +18 -0
- data/lib/pdfrb/model/type/rich_media_command.rb +19 -0
- data/lib/pdfrb/model/type/rich_media_configuration.rb +32 -0
- data/lib/pdfrb/model/type/rich_media_content.rb +28 -0
- data/lib/pdfrb/model/type/rich_media_cue_point.rb +18 -0
- data/lib/pdfrb/model/type/rich_media_deactivation.rb +17 -0
- data/lib/pdfrb/model/type/rich_media_instance.rb +33 -0
- data/lib/pdfrb/model/type/rich_media_presentation.rb +29 -0
- data/lib/pdfrb/model/type/rich_media_settings.rb +33 -0
- data/lib/pdfrb/model/type/rich_media_window.rb +20 -0
- data/lib/pdfrb/model/type/screen_annotation.rb +19 -0
- data/lib/pdfrb/model/type/separation.rb +25 -0
- data/lib/pdfrb/model/type/sig_field_lock.rb +25 -0
- data/lib/pdfrb/model/type/sig_field_seed_value.rb +25 -0
- data/lib/pdfrb/model/type/signature.rb +65 -0
- data/lib/pdfrb/model/type/signature_build.rb +86 -0
- data/lib/pdfrb/model/type/signature_field.rb +17 -0
- data/lib/pdfrb/model/type/software_identifier.rb +19 -0
- data/lib/pdfrb/model/type/sound.rb +38 -0
- data/lib/pdfrb/model/type/sound_annotation.rb +21 -0
- data/lib/pdfrb/model/type/square_annotation.rb +24 -0
- data/lib/pdfrb/model/type/square_circle.rb +13 -0
- data/lib/pdfrb/model/type/squiggly_annotation.rb +11 -0
- data/lib/pdfrb/model/type/stamp_annotation.rb +19 -0
- data/lib/pdfrb/model/type/strikeout_annotation.rb +11 -0
- data/lib/pdfrb/model/type/struct_elem.rb +75 -0
- data/lib/pdfrb/model/type/struct_tree_root.rb +34 -0
- data/lib/pdfrb/model/type/structure_attributes.rb +44 -0
- data/lib/pdfrb/model/type/structure_element_kid.rb +33 -0
- data/lib/pdfrb/model/type/text_annotation.rb +25 -0
- data/lib/pdfrb/model/type/text_appearance.rb +9 -0
- data/lib/pdfrb/model/type/text_field.rb +21 -0
- data/lib/pdfrb/model/type/text_markup_annotation.rb +30 -0
- data/lib/pdfrb/model/type/three_d_activation.rb +32 -0
- data/lib/pdfrb/model/type/three_d_animation_style.rb +24 -0
- data/lib/pdfrb/model/type/three_d_background.rb +28 -0
- data/lib/pdfrb/model/type/three_d_cross_section.rb +25 -0
- data/lib/pdfrb/model/type/three_d_lighting_scheme.rb +26 -0
- data/lib/pdfrb/model/type/three_d_measure.rb +20 -0
- data/lib/pdfrb/model/type/three_d_measure_3dc.rb +23 -0
- data/lib/pdfrb/model/type/three_d_measure_ad3.rb +14 -0
- data/lib/pdfrb/model/type/three_d_measure_ld3.rb +14 -0
- data/lib/pdfrb/model/type/three_d_measure_pd3.rb +20 -0
- data/lib/pdfrb/model/type/three_d_measure_rd3.rb +14 -0
- data/lib/pdfrb/model/type/three_d_node.rb +37 -0
- data/lib/pdfrb/model/type/three_d_reference.rb +21 -0
- data/lib/pdfrb/model/type/three_d_render_mode.rb +34 -0
- data/lib/pdfrb/model/type/three_d_stream.rb +48 -0
- data/lib/pdfrb/model/type/three_d_units.rb +18 -0
- data/lib/pdfrb/model/type/three_d_view.rb +40 -0
- data/lib/pdfrb/model/type/to_unicode_cmap_stream.rb +23 -0
- data/lib/pdfrb/model/type/transition.rb +68 -0
- data/lib/pdfrb/model/type/underline_annotation.rb +11 -0
- data/lib/pdfrb/model/type/ur_transform_parameters.rb +33 -0
- data/lib/pdfrb/model/type/uri_dict.rb +18 -0
- data/lib/pdfrb/model/type/url_alias.rb +19 -0
- data/lib/pdfrb/model/type/variable_text_field.rb +47 -0
- data/lib/pdfrb/model/type/viewer_preferences.rb +42 -0
- data/lib/pdfrb/model/type/watermark_annotation.rb +13 -0
- data/lib/pdfrb/model/type/widget_annotation.rb +48 -0
- data/lib/pdfrb/model/type/widget_appearance.rb +9 -0
- data/lib/pdfrb/model/type/xobject_form.rb +41 -0
- data/lib/pdfrb/model/type/xobject_image.rb +56 -0
- data/lib/pdfrb/model/type/xref_stream.rb +37 -0
- data/lib/pdfrb/model/type.rb +286 -6
- data/lib/pdfrb/serializer.rb +2 -2
- data/lib/pdfrb/source/tokenizer.rb +0 -2
- data/lib/pdfrb/task/benchmark.rb +83 -0
- data/lib/pdfrb/task/extract_text.rb +1 -1
- data/lib/pdfrb/task/generate_corpus.rb +130 -0
- data/lib/pdfrb/task/memory_profile.rb +84 -0
- data/lib/pdfrb/task/optimize.rb +97 -7
- data/lib/pdfrb/task.rb +3 -3
- data/lib/pdfrb/test_utils.rb +112 -0
- data/lib/pdfrb/validator.rb +82 -0
- data/lib/pdfrb/version.rb +1 -1
- data/lib/pdfrb/writer.rb +117 -27
- data/lib/pdfrb/xmp/packet.rb +122 -0
- data/lib/pdfrb/xmp/schemas.rb +96 -0
- data/lib/pdfrb/xmp.rb +44 -0
- data/lib/pdfrb/xref_section.rb +2 -2
- data/lib/pdfrb.rb +25 -53
- data/pdfrb.gemspec +45 -0
- data/script/apply_fixes.sh +843 -0
- data/script/make_jpeg_fixture.rb +53 -0
- data/script/make_png_fixture.rb +25 -0
- metadata +312 -2
|
@@ -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,48 @@
|
|
|
1
|
+
# Releasing pdfrb
|
|
2
|
+
|
|
3
|
+
Releases are driven by git tags. The release workflow is at
|
|
4
|
+
`.github/workflows/release.yml` and runs on tag push (or manual dispatch
|
|
5
|
+
for an existing tag).
|
|
6
|
+
|
|
7
|
+
## Publish flow
|
|
8
|
+
|
|
9
|
+
1. Ensure `lib/pdfrb/version.rb` has the target version.
|
|
10
|
+
2. Merge the version-bump change via a PR (never commit directly to main).
|
|
11
|
+
3. When the PR lands, tag the merged commit:
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
git tag v$(ruby -Ilib -e 'require "pdfrb/version"; print Pdfrb::VERSION')
|
|
15
|
+
git push origin v<VERSION>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
4. The `Release` workflow fires automatically:
|
|
19
|
+
- Verifies tag ↔ `lib/pdfrb/version.rb` match.
|
|
20
|
+
- Builds the gem (`bundle exec rake build`).
|
|
21
|
+
- Publishes to RubyGems via OIDC trusted publishing (no stored API key).
|
|
22
|
+
- Creates a GitHub release with auto-generated notes.
|
|
23
|
+
|
|
24
|
+
## Trusted publishing (OIDC)
|
|
25
|
+
|
|
26
|
+
The workflow uses `rubygems/configure-rubygems-credentials` with OIDC.
|
|
27
|
+
To enable, on RubyGems:
|
|
28
|
+
|
|
29
|
+
1. Open the `pdfrb` gem settings.
|
|
30
|
+
2. Add the GitHub workflow as a trusted publisher:
|
|
31
|
+
- Repository: `claricle/pdfrb`
|
|
32
|
+
- Workflow filename: `release.yml`
|
|
33
|
+
- Environment: (leave blank)
|
|
34
|
+
|
|
35
|
+
Until that is configured, the `Publish to RubyGems` step will fail.
|
|
36
|
+
|
|
37
|
+
## Manual dispatch
|
|
38
|
+
|
|
39
|
+
The workflow accepts a `tag` input. Run it from the Actions UI on a
|
|
40
|
+
previously-pushed tag if the auto-trigger missed (e.g., the workflow
|
|
41
|
+
file was added after the tag was pushed).
|
|
42
|
+
|
|
43
|
+
## Pre-release checklist
|
|
44
|
+
|
|
45
|
+
- `bundle exec rake` is green.
|
|
46
|
+
- `lib/pdfrb/version.rb` matches the intended tag.
|
|
47
|
+
- `CHANGELOG.md` has an entry for the new version.
|
|
48
|
+
- No uncommitted changes on `main`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Action
|
|
5
|
+
# Base action builder. Subclasses define +action_type+ (the /S value)
|
|
6
|
+
# and +to_pdf+ (type-specific serialization).
|
|
7
|
+
class Base
|
|
8
|
+
class << self
|
|
9
|
+
# @return [Symbol] the /S value (e.g. :GoTo, :URI).
|
|
10
|
+
def action_type
|
|
11
|
+
raise NotImplementedError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def register_as(name = action_type)
|
|
15
|
+
Action.register(name, self)
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Action
|
|
5
|
+
# Concrete action types (ISO 32000-2 §12.6). Each class defines
|
|
6
|
+
# its /S value and type-specific fields, then registers itself.
|
|
7
|
+
|
|
8
|
+
# GoTo — jump to a destination in the current document. §12.6.4.2
|
|
9
|
+
class GoTo < Base
|
|
10
|
+
class << self
|
|
11
|
+
def action_type; :GoTo; end
|
|
12
|
+
|
|
13
|
+
def to_pdf(dest:)
|
|
14
|
+
{ S: :GoTo, D: dest }
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
register_as
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# URI — open a Uniform Resource Identifier. §12.6.4.7
|
|
21
|
+
class URI < Base
|
|
22
|
+
class << self
|
|
23
|
+
def action_type; :URI; end
|
|
24
|
+
|
|
25
|
+
def to_pdf(uri:, is_map: false)
|
|
26
|
+
{ S: :URI, URI: uri, IsMap: is_map }.compact
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
register_as
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Launch — launch an external application. §12.6.4.5
|
|
33
|
+
class Launch < Base
|
|
34
|
+
class << self
|
|
35
|
+
def action_type; :Launch; end
|
|
36
|
+
|
|
37
|
+
def to_pdf(file_spec:, new_window: nil)
|
|
38
|
+
payload = { S: :Launch, F: file_spec }
|
|
39
|
+
payload[:NewWindow] = new_window unless new_window.nil?
|
|
40
|
+
payload
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
register_as
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Named — execute a named action predefined by the viewer. §12.6.4.11
|
|
47
|
+
class Named < Base
|
|
48
|
+
class << self
|
|
49
|
+
def action_type; :Named; end
|
|
50
|
+
|
|
51
|
+
def to_pdf(name:)
|
|
52
|
+
{ S: :Named, N: name }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
register_as
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# GoToR — go to a destination in a remote document. §12.6.4.3
|
|
59
|
+
class GoToR < Base
|
|
60
|
+
class << self
|
|
61
|
+
def action_type; :GoToR; end
|
|
62
|
+
|
|
63
|
+
def to_pdf(file_spec:, dest:, new_window: nil)
|
|
64
|
+
payload = { S: :GoToR, F: file_spec, D: dest }
|
|
65
|
+
payload[:NewWindow] = new_window unless new_window.nil?
|
|
66
|
+
payload
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
register_as
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# SubmitForm — submit form data to a URL. §12.7.6.2
|
|
73
|
+
class SubmitForm < Base
|
|
74
|
+
class << self
|
|
75
|
+
def action_type; :SubmitForm; end
|
|
76
|
+
|
|
77
|
+
def to_pdf(url:, flags: 0)
|
|
78
|
+
{ S: :SubmitForm, F: url, Flags: flags }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
register_as
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# ResetForm — reset form fields to defaults. §12.7.6.3
|
|
85
|
+
class ResetForm < Base
|
|
86
|
+
class << self
|
|
87
|
+
def action_type; :ResetForm; end
|
|
88
|
+
|
|
89
|
+
def to_pdf(fields: nil, flags: 0)
|
|
90
|
+
payload = { S: :ResetForm, Flags: flags }
|
|
91
|
+
payload[:Fields] = fields if fields
|
|
92
|
+
payload
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
register_as
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# JavaScript — execute JavaScript. §12.6.4.16
|
|
99
|
+
# NOTE: PDF/A prohibits this; included for completeness.
|
|
100
|
+
class JavaScript < Base
|
|
101
|
+
class << self
|
|
102
|
+
def action_type; :JavaScript; end
|
|
103
|
+
|
|
104
|
+
def to_pdf(script:)
|
|
105
|
+
{ S: :JavaScript, JS: script }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
register_as
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Hide — show or hide an annotation. §12.6.4.9
|
|
112
|
+
class Hide < Base
|
|
113
|
+
class << self
|
|
114
|
+
def action_type; :Hide; end
|
|
115
|
+
|
|
116
|
+
def to_pdf(target:, hide: true)
|
|
117
|
+
{ S: :Hide, T: target, H: hide }
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
register_as
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# ImportData — import FDF/XFDF form data. §12.7.6.4
|
|
124
|
+
class ImportData < Base
|
|
125
|
+
class << self
|
|
126
|
+
def action_type; :ImportData; end
|
|
127
|
+
|
|
128
|
+
def to_pdf(file_spec:)
|
|
129
|
+
{ S: :ImportData, F: file_spec }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
register_as
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# SetOCGState — toggle optional-content groups. §12.6.4.13
|
|
136
|
+
class SetOCGState < Base
|
|
137
|
+
class << self
|
|
138
|
+
def action_type; :SetOCGState; end
|
|
139
|
+
|
|
140
|
+
def to_pdf(state:, preserve_rb: false)
|
|
141
|
+
payload = { S: :SetOCGState, State: state }
|
|
142
|
+
payload[:PreserveRB] = preserve_rb unless preserve_rb == false
|
|
143
|
+
payload
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
register_as
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Trans — page transition for slide-show mode. §12.4.3
|
|
150
|
+
class Trans < Base
|
|
151
|
+
class << self
|
|
152
|
+
def action_type; :Trans; end
|
|
153
|
+
|
|
154
|
+
def to_pdf(style:, duration: nil, direction: nil)
|
|
155
|
+
trans = { S: style }
|
|
156
|
+
trans[:D] = duration if duration
|
|
157
|
+
trans[:Di] = direction if direction
|
|
158
|
+
{ S: :Trans, Trans: trans }
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
register_as
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# GoToE — go to a destination in an embedded file. §12.6.4.4 (PDF 1.6+)
|
|
165
|
+
class GoToE < Base
|
|
166
|
+
class << self
|
|
167
|
+
def action_type; :GoToE; end
|
|
168
|
+
|
|
169
|
+
def to_pdf(file_spec:, dest:, new_window: nil)
|
|
170
|
+
payload = { S: :GoToE, F: file_spec, D: dest }
|
|
171
|
+
payload[:NewWindow] = new_window unless new_window.nil?
|
|
172
|
+
payload
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
register_as
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
data/lib/pdfrb/action.rb
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
# Actions (ISO 32000-2 §12.6). An action specifies an interactive
|
|
5
|
+
# behavior: jump to a destination, open a URI, launch an app, etc.
|
|
6
|
+
#
|
|
7
|
+
# Each action type is a value object that serializes to a PDF action
|
|
8
|
+
# dictionary with /S (action type) and type-specific keys.
|
|
9
|
+
module Action
|
|
10
|
+
autoload :Base, "pdfrb/action/base"
|
|
11
|
+
# Each action builder class lives in types.rb but is referenced
|
|
12
|
+
# directly by callers. Autoload from that file.
|
|
13
|
+
autoload :GoTo, "pdfrb/action/types"
|
|
14
|
+
autoload :URI, "pdfrb/action/types"
|
|
15
|
+
autoload :Launch, "pdfrb/action/types"
|
|
16
|
+
autoload :Named, "pdfrb/action/types"
|
|
17
|
+
autoload :GoToR, "pdfrb/action/types"
|
|
18
|
+
autoload :SubmitForm, "pdfrb/action/types"
|
|
19
|
+
autoload :ResetForm, "pdfrb/action/types"
|
|
20
|
+
autoload :JavaScript, "pdfrb/action/types"
|
|
21
|
+
autoload :Hide, "pdfrb/action/types"
|
|
22
|
+
autoload :ImportData, "pdfrb/action/types"
|
|
23
|
+
autoload :SetOCGState, "pdfrb/action/types"
|
|
24
|
+
autoload :Trans, "pdfrb/action/types"
|
|
25
|
+
autoload :GoToE, "pdfrb/action/types"
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
def registry
|
|
29
|
+
@registry ||= {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def register(name, klass)
|
|
33
|
+
registry[name.to_sym] = klass
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def [](name)
|
|
37
|
+
key = name.to_sym
|
|
38
|
+
result = registry[key]
|
|
39
|
+
return result if result
|
|
40
|
+
|
|
41
|
+
# Lazy-load on miss: trigger autoload of GoTo which loads
|
|
42
|
+
# the entire types.rb file and registers all subtypes.
|
|
43
|
+
GoTo unless @loaded
|
|
44
|
+
@loaded = true
|
|
45
|
+
registry[key]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def types
|
|
49
|
+
GoTo unless @loaded
|
|
50
|
+
@loaded = true
|
|
51
|
+
registry.keys
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|