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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- 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 +291 -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/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 +24 -54
- 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 +311 -2
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Pdfrb
|
|
4
4
|
class Document
|
|
5
|
-
# Annotations facade
|
|
5
|
+
# Annotations facade. Adds and enumerates annotations on pages.
|
|
6
6
|
class Annotations
|
|
7
7
|
attr_reader :document
|
|
8
8
|
|
|
@@ -27,8 +27,88 @@ module Pdfrb
|
|
|
27
27
|
annot
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
# Sticky-note / comment text annotation.
|
|
31
|
+
def add_text_note(page, rect:, contents:, open: false)
|
|
32
|
+
annot = add(page, subtype: :Text, rect: rect, contents: contents)
|
|
33
|
+
annot.value[:Open] = open unless open == false
|
|
34
|
+
annot
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Hyperlink annotation pointing at a destination.
|
|
38
|
+
def add_link(page, rect:, dest: nil, uri: nil, highlight: :Invert)
|
|
39
|
+
annot = add(page, subtype: :Link, rect: rect)
|
|
40
|
+
annot.value[:H] = highlight
|
|
41
|
+
if dest
|
|
42
|
+
annot.value[:Dest] = dest
|
|
43
|
+
elsif uri
|
|
44
|
+
action = document.add(
|
|
45
|
+
{ Type: :Action, S: :URI, URI: uri },
|
|
46
|
+
type: Pdfrb::Model::Type::Action
|
|
47
|
+
)
|
|
48
|
+
annot.value[:A] = Pdfrb::Model::Reference.new(action.oid, action.gen)
|
|
49
|
+
end
|
|
50
|
+
annot
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Free-text annotation showing inline text on the page.
|
|
54
|
+
def add_free_text(page, rect:, contents:, font: nil, font_size: nil, color: nil)
|
|
55
|
+
annot = document.add(
|
|
56
|
+
{
|
|
57
|
+
Type: :Annot, Subtype: :FreeText, Rect: rect,
|
|
58
|
+
P: Pdfrb::Model::Reference.new(page.oid, page.gen),
|
|
59
|
+
Contents: contents
|
|
60
|
+
},
|
|
61
|
+
type: Pdfrb::Model::Type::FreeTextAnnotation
|
|
62
|
+
)
|
|
63
|
+
da_parts = []
|
|
64
|
+
da_parts << "/#{font} #{font_size} Tf" if font && font_size
|
|
65
|
+
da_parts << "#{color.join(' ')} rg" if color
|
|
66
|
+
annot.value[:DA] = da_parts.join(" ") unless da_parts.empty?
|
|
67
|
+
annots = (page.value[:Annots] ||= [])
|
|
68
|
+
annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
|
|
69
|
+
annot
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Highlight text-markup annotation over the given quad points.
|
|
73
|
+
def add_highlight(page, quad_points:, contents: nil)
|
|
74
|
+
annot = document.add(
|
|
75
|
+
{
|
|
76
|
+
Type: :Annot, Subtype: :Highlight,
|
|
77
|
+
QuadPoints: quad_points,
|
|
78
|
+
P: Pdfrb::Model::Reference.new(page.oid, page.gen),
|
|
79
|
+
Contents: contents
|
|
80
|
+
}.compact,
|
|
81
|
+
type: Pdfrb::Model::Type::HighlightAnnotation
|
|
82
|
+
)
|
|
83
|
+
annots = (page.value[:Annots] ||= [])
|
|
84
|
+
annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
|
|
85
|
+
annot
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Stamp annotation (e.g. DRAFT, APPROVED, CONFIDENTIAL).
|
|
89
|
+
def add_stamp(page, rect:, name: :Draft, contents: nil)
|
|
90
|
+
annot = document.add(
|
|
91
|
+
{
|
|
92
|
+
Type: :Annot, Subtype: :Stamp, Rect: rect, Name: name,
|
|
93
|
+
P: Pdfrb::Model::Reference.new(page.oid, page.gen),
|
|
94
|
+
Contents: contents
|
|
95
|
+
}.compact,
|
|
96
|
+
type: Pdfrb::Model::Type::StampAnnotation
|
|
97
|
+
)
|
|
98
|
+
annots = (page.value[:Annots] ||= [])
|
|
99
|
+
annots << Pdfrb::Model::Reference.new(annot.oid, annot.gen)
|
|
100
|
+
annot
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def count(page)
|
|
104
|
+
annots = page.value[:Annots]
|
|
105
|
+
return 0 unless annots
|
|
106
|
+
|
|
107
|
+
annots.is_a?(::Array) ? annots.length : 1
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def each(page, &block)
|
|
111
|
+
return enum_for(:each, page) unless block
|
|
32
112
|
|
|
33
113
|
annots = page.value[:Annots]
|
|
34
114
|
return self unless annots
|
|
@@ -39,6 +119,43 @@ module Pdfrb
|
|
|
39
119
|
end
|
|
40
120
|
self
|
|
41
121
|
end
|
|
122
|
+
|
|
123
|
+
# Iterate annotations of a specific subtype across the whole doc.
|
|
124
|
+
def each_of_subtype(subtype, &block)
|
|
125
|
+
return enum_for(:each_of_subtype, subtype) unless block
|
|
126
|
+
|
|
127
|
+
document.pages.each do |page|
|
|
128
|
+
each(page) do |annot|
|
|
129
|
+
next unless annot[:Subtype]&.to_sym == subtype
|
|
130
|
+
|
|
131
|
+
yield annot
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
self
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Iterate every link annotation in the document.
|
|
138
|
+
def each_link(&block)
|
|
139
|
+
return enum_for(:each_link) unless block
|
|
140
|
+
|
|
141
|
+
each_of_subtype(:Link, &block)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Iterate every widget (form) annotation in the document.
|
|
145
|
+
def each_widget(&block)
|
|
146
|
+
return enum_for(:each_widget) unless block
|
|
147
|
+
|
|
148
|
+
each_of_subtype(:Widget, &block)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Iterate every text-markup annotation in the document.
|
|
152
|
+
def each_text_markup(&block)
|
|
153
|
+
return enum_for(:each_text_markup) unless block
|
|
154
|
+
|
|
155
|
+
%i[Highlight Underline Squiggly StrikeOut].each do |sub|
|
|
156
|
+
each_of_subtype(sub, &block)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
42
159
|
end
|
|
43
160
|
end
|
|
44
161
|
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
class Document
|
|
5
|
+
# Associated Files (AF) facade. PDF 2.0 introduced /AF arrays on
|
|
6
|
+
# Catalog, Page, and StructElem to declare the relationship between
|
|
7
|
+
# embedded files and the context they appear in.
|
|
8
|
+
#
|
|
9
|
+
# Relationship types (ISO 32000-2 §7.11.3):
|
|
10
|
+
# :Source — source document for the content
|
|
11
|
+
# :Data — data file referenced by the content
|
|
12
|
+
# :Alternative — alternative representation
|
|
13
|
+
# :Supplement — supplemental information
|
|
14
|
+
# :Unspecified — relationship not specified
|
|
15
|
+
#
|
|
16
|
+
# App Note 002: https://github.com/pdf-association/appnote-pdf20-002-af
|
|
17
|
+
class AssociatedFiles
|
|
18
|
+
RELATIONSHIP_TYPES = %i[
|
|
19
|
+
Source Data Alternative Supplement Unspecified
|
|
20
|
+
Encrypted Payload FormData Schema Template
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
attr_reader :document
|
|
24
|
+
|
|
25
|
+
def initialize(document)
|
|
26
|
+
@document = document
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Associate a filespec with the Catalog-level /AF array.
|
|
30
|
+
# @param filespec_ref [Pdfrb::Model::Reference] the /Filespec ref.
|
|
31
|
+
# @param relationship [Symbol] one of RELATIONSHIP_TYPES.
|
|
32
|
+
def add_to_catalog(filespec_ref, relationship: :Unspecified)
|
|
33
|
+
ensure_relationship(filespec_ref, relationship)
|
|
34
|
+
append_to_af_array(document.catalog, filespec_ref)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Associate a filespec with a specific page's /AF array.
|
|
38
|
+
def add_to_page(page, filespec_ref, relationship: :Unspecified)
|
|
39
|
+
ensure_relationship(filespec_ref, relationship)
|
|
40
|
+
append_to_af_array(page, filespec_ref)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Associate a filespec with a structure element's /AF array.
|
|
44
|
+
def add_to_element(struct_elem, filespec_ref, relationship: :Unspecified)
|
|
45
|
+
ensure_relationship(filespec_ref, relationship)
|
|
46
|
+
append_to_af_array(struct_elem, filespec_ref)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Convenience: create a filespec + embedded file from raw bytes,
|
|
50
|
+
# then associate it at the catalog level.
|
|
51
|
+
# @return [Pdfrb::Model::Reference] the filespec reference.
|
|
52
|
+
def embed(filename:, data:, relationship: :Unspecified,
|
|
53
|
+
description: nil, mime_type: nil)
|
|
54
|
+
filespec = document.files.add(data, name: filename,
|
|
55
|
+
description: description,
|
|
56
|
+
mime_type: mime_type)
|
|
57
|
+
ref = Pdfrb::Model::Reference.new(filespec.oid, filespec.gen)
|
|
58
|
+
filespec.value[:AFRelationship] = relationship
|
|
59
|
+
add_to_catalog(ref, relationship: relationship)
|
|
60
|
+
ref
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# List all catalog-level AF filespecs.
|
|
64
|
+
def catalog_files
|
|
65
|
+
read_af_array(document.catalog)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
def ensure_relationship(filespec_ref, relationship)
|
|
71
|
+
unless RELATIONSHIP_TYPES.include?(relationship)
|
|
72
|
+
raise ArgumentError, "invalid AF relationship: #{relationship}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
filespec = document.object(filespec_ref)
|
|
76
|
+
return unless filespec.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
77
|
+
|
|
78
|
+
filespec.value[:AFRelationship] = relationship
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def append_to_af_array(dict_obj, ref)
|
|
82
|
+
af = dict_obj.value[:AF]
|
|
83
|
+
if af.nil?
|
|
84
|
+
dict_obj.value[:AF] = [ref]
|
|
85
|
+
elsif af.is_a?(::Array)
|
|
86
|
+
af << ref
|
|
87
|
+
else
|
|
88
|
+
dict_obj.value[:AF] = [af, ref]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def read_af_array(dict_obj)
|
|
93
|
+
af = dict_obj.value[:AF]
|
|
94
|
+
return [] unless af
|
|
95
|
+
|
|
96
|
+
refs = af.is_a?(::Array) ? af : [af]
|
|
97
|
+
refs.filter_map do |ref|
|
|
98
|
+
obj = ref.is_a?(Pdfrb::Model::Reference) ? document.object(ref) : ref
|
|
99
|
+
obj if obj.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
class Document
|
|
5
|
+
# Facade for color space management. Embeds ICC profiles, registers
|
|
6
|
+
# named color spaces in page Resources, and provides lookup.
|
|
7
|
+
class Colors
|
|
8
|
+
attr_reader :document
|
|
9
|
+
|
|
10
|
+
def initialize(document)
|
|
11
|
+
@document = document
|
|
12
|
+
@next_cs_number = 1
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Embed an ICC profile as a stream and return the color space
|
|
16
|
+
# array [/ICCBased <ref>] for use in Resources.
|
|
17
|
+
#
|
|
18
|
+
# @param icc_bytes [String] raw ICC profile bytes.
|
|
19
|
+
# @param alternate [Symbol, nil] fallback color space
|
|
20
|
+
# (:DeviceRGB, :DeviceCMYK, :DeviceGray, :Lab). Derived from
|
|
21
|
+
# the profile header if nil.
|
|
22
|
+
# @return [Pdfrb::Model::PdfArray] the [/ICCBased <ref>] array.
|
|
23
|
+
def embed_icc_profile(icc_bytes, alternate: nil)
|
|
24
|
+
profile = Pdfrb::Color::ICCProfile.new(icc_bytes, alternate: alternate)
|
|
25
|
+
stream = document.add(
|
|
26
|
+
{ **profile.stream_dictionary_fields,
|
|
27
|
+
Length: profile.raw_data.bytesize },
|
|
28
|
+
type: Pdfrb::Model::Cos::Stream
|
|
29
|
+
)
|
|
30
|
+
stream.stream = profile.raw_data
|
|
31
|
+
Pdfrb::Model::PdfArray.new([
|
|
32
|
+
:ICCBased,
|
|
33
|
+
Pdfrb::Model::Reference.new(stream.oid, stream.gen),
|
|
34
|
+
])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Register a color space in a page's Resources /ColorSpace dict
|
|
38
|
+
# and return the name (e.g. :CS1) for use in content streams.
|
|
39
|
+
#
|
|
40
|
+
# @param page [Pdfrb::Model::Cos::Dictionary] the target page.
|
|
41
|
+
# @param color_space the color space value (name, array, or ref).
|
|
42
|
+
# @return [Symbol] the registered name.
|
|
43
|
+
def register(page, color_space)
|
|
44
|
+
resources = ensure_resources(page)
|
|
45
|
+
cs_dict = resources.value[:ColorSpace]
|
|
46
|
+
cs_dict = ensure_color_space_dict(resources, cs_dict)
|
|
47
|
+
|
|
48
|
+
name = cs_name
|
|
49
|
+
cs_dict[name] = color_space
|
|
50
|
+
name
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def ensure_resources(page)
|
|
56
|
+
resources = page.value[:Resources]
|
|
57
|
+
return resources if resources.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
58
|
+
|
|
59
|
+
resources_hash = if resources.is_a?(Pdfrb::Model::Reference)
|
|
60
|
+
document.object(resources)&.value
|
|
61
|
+
else
|
|
62
|
+
resources
|
|
63
|
+
end
|
|
64
|
+
if resources_hash.nil?
|
|
65
|
+
resources_hash = {}
|
|
66
|
+
page.value[:Resources] = resources_hash
|
|
67
|
+
end
|
|
68
|
+
wrap_resources(page, resources_hash)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def wrap_resources(page, hash)
|
|
72
|
+
existing = page.value[:Resources]
|
|
73
|
+
return existing if existing.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
74
|
+
|
|
75
|
+
wrapped = Pdfrb::Model::Cos::Dictionary.new(hash)
|
|
76
|
+
page.value[:Resources] = wrapped
|
|
77
|
+
wrapped
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def ensure_color_space_dict(resources, cs_dict)
|
|
81
|
+
return cs_dict if cs_dict.is_a?(::Hash) || cs_dict.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
82
|
+
|
|
83
|
+
cs_hash = {}
|
|
84
|
+
resources.value[:ColorSpace] = cs_hash
|
|
85
|
+
cs_hash
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def cs_name
|
|
89
|
+
name = :"CS#{@next_cs_number}"
|
|
90
|
+
@next_cs_number += 1
|
|
91
|
+
name
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Pdfrb
|
|
4
4
|
class Document
|
|
5
|
-
# Named-destinations facade
|
|
5
|
+
# Named-destinations facade. Manages both name-tree destinations
|
|
6
|
+
# (Catalog /Names /Dests) and the explicit /Dests dictionary.
|
|
6
7
|
class Destinations
|
|
7
8
|
attr_reader :document
|
|
8
9
|
|
|
@@ -10,12 +11,133 @@ module Pdfrb
|
|
|
10
11
|
@document = document
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
# Look up a named destination by name. Returns the destination
|
|
15
|
+
# array or nil.
|
|
13
16
|
def [](name)
|
|
14
|
-
|
|
15
|
-
return
|
|
17
|
+
dests_dict = resolved_explicit_dict
|
|
18
|
+
return dests_dict[name] if dests_dict && dests_dict[name]
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
name_tree = resolved_name_tree
|
|
21
|
+
lookup_in_name_tree(name_tree, name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Add an explicit destination under +name+. Creates the /Dests
|
|
25
|
+
# dictionary if absent. +destination+ is typically an Array
|
|
26
|
+
# [page_ref, fit_keyword, *args].
|
|
27
|
+
def add(name, destination)
|
|
28
|
+
ensure_dictionaries
|
|
29
|
+
catalog = document.catalog
|
|
30
|
+
catalog.value[:Dests] ||= {}
|
|
31
|
+
catalog.value[:Dests][name.to_sym] = destination
|
|
32
|
+
name.to_sym
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Enumerate all destination names (from both /Dests and /Names/Dests).
|
|
36
|
+
def each_name(&)
|
|
37
|
+
return enum_for(:each_name) unless block_given?
|
|
38
|
+
|
|
39
|
+
seen = Set.new
|
|
40
|
+
explicit = resolved_explicit_dict
|
|
41
|
+
explicit&.each_key do |k|
|
|
42
|
+
next if seen.include?(k)
|
|
43
|
+
|
|
44
|
+
seen << k
|
|
45
|
+
yield k
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
name_tree = resolved_name_tree
|
|
49
|
+
each_name_tree_key(name_tree) do |k|
|
|
50
|
+
next if seen.include?(k)
|
|
51
|
+
|
|
52
|
+
seen << k
|
|
53
|
+
yield k
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def names
|
|
58
|
+
each_name.to_a
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def empty?
|
|
62
|
+
names.empty?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def count
|
|
66
|
+
names.size
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def ensure_dictionaries
|
|
72
|
+
catalog = document.catalog
|
|
73
|
+
catalog.value[:Names] ||= {}
|
|
74
|
+
catalog.value[:Names][:Dests] ||= {}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def resolved_explicit_dict
|
|
78
|
+
catalog = document.catalog
|
|
79
|
+
d = catalog.value[:Dests]
|
|
80
|
+
return nil unless d
|
|
81
|
+
|
|
82
|
+
d.is_a?(Pdfrb::Model::Reference) ? document.object(d) : d
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def resolved_name_tree
|
|
86
|
+
catalog = document.catalog
|
|
87
|
+
names = catalog.value[:Names]
|
|
88
|
+
return nil unless names
|
|
89
|
+
|
|
90
|
+
names = document.object(names) if names.is_a?(Pdfrb::Model::Reference)
|
|
91
|
+
return nil unless names
|
|
92
|
+
|
|
93
|
+
d = names.is_a?(Pdfrb::Model::Cos::Dictionary) ? names.value[:Dests] : names[:Dests]
|
|
94
|
+
return nil unless d
|
|
95
|
+
|
|
96
|
+
d.is_a?(Pdfrb::Model::Reference) ? document.object(d) : d
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def lookup_in_name_tree(node, name)
|
|
100
|
+
return nil unless node
|
|
101
|
+
|
|
102
|
+
if node.is_a?(Pdfrb::Model::Cos::Dictionary) && node.value[:Names]
|
|
103
|
+
arr = node.value[:Names]
|
|
104
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
105
|
+
arr.each_slice(2) { |k, v| return v if k == name }
|
|
106
|
+
elsif node.is_a?(Pdfrb::Model::Cos::Dictionary) && node.value[:Kids]
|
|
107
|
+
arr = node.value[:Kids]
|
|
108
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
109
|
+
arr.each do |kid_ref|
|
|
110
|
+
kid = kid_ref.is_a?(Pdfrb::Model::Reference) ? document.object(kid_ref) : kid_ref
|
|
111
|
+
result = lookup_in_name_tree(kid, name)
|
|
112
|
+
return result if result
|
|
113
|
+
end
|
|
114
|
+
elsif node.is_a?(Hash) && node[:Names]
|
|
115
|
+
arr = node[:Names]
|
|
116
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
117
|
+
arr.each_slice(2) { |k, v| return v if k == name }
|
|
118
|
+
end
|
|
119
|
+
nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def each_name_tree_key(node, &block)
|
|
123
|
+
return unless node
|
|
124
|
+
|
|
125
|
+
if node.is_a?(Pdfrb::Model::Cos::Dictionary) && node.value[:Names]
|
|
126
|
+
arr = node.value[:Names]
|
|
127
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
128
|
+
arr.each_slice(2) { |k, _v| yield k }
|
|
129
|
+
elsif node.is_a?(Pdfrb::Model::Cos::Dictionary) && node.value[:Kids]
|
|
130
|
+
arr = node.value[:Kids]
|
|
131
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
132
|
+
arr.each do |kid_ref|
|
|
133
|
+
kid = kid_ref.is_a?(Pdfrb::Model::Reference) ? document.object(kid_ref) : kid_ref
|
|
134
|
+
each_name_tree_key(kid, &block)
|
|
135
|
+
end
|
|
136
|
+
elsif node.is_a?(Hash) && node[:Names]
|
|
137
|
+
arr = node[:Names]
|
|
138
|
+
arr = arr.to_a if arr.is_a?(Pdfrb::Model::PdfArray)
|
|
139
|
+
arr.each_slice(2) { |k, _v| yield k }
|
|
140
|
+
end
|
|
19
141
|
end
|
|
20
142
|
end
|
|
21
143
|
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
class Document
|
|
5
|
+
# Catalog display controls. Sets viewer behavior: hide toolbar,
|
|
6
|
+
# page layout, page mode, and open-action destination.
|
|
7
|
+
#
|
|
8
|
+
# /ViewerPreferences — fine-grained viewer controls
|
|
9
|
+
# /PageLayout — how pages are laid out in the viewer
|
|
10
|
+
# /PageMode — which panels are visible on open
|
|
11
|
+
# /OpenAction — initial destination or action
|
|
12
|
+
class Display
|
|
13
|
+
PAGE_LAYOUTS = %i[
|
|
14
|
+
SinglePage OneColumn TwoColumnLeft TwoColumnRight
|
|
15
|
+
TwoPageLeft TwoPageRight
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
PAGE_MODES = %i[
|
|
19
|
+
UseNone UseOutlines UseThumbs FullScreen UseOC UseAttachments
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
NON_FULLSCREEN_PAGE_MODES = %i[UseNone UseOutlines UseThumbs UseOC].freeze
|
|
23
|
+
|
|
24
|
+
DIRECTIONS = %i[L2R R2L].freeze
|
|
25
|
+
|
|
26
|
+
attr_reader :document
|
|
27
|
+
|
|
28
|
+
def initialize(document)
|
|
29
|
+
@document = document
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param layout [Symbol] one of PAGE_LAYOUTS.
|
|
33
|
+
def page_layout=(layout)
|
|
34
|
+
raise ArgumentError, "invalid page layout: #{layout}" unless PAGE_LAYOUTS.include?(layout)
|
|
35
|
+
|
|
36
|
+
document.catalog.value[:PageLayout] = layout
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param mode [Symbol] one of PAGE_MODES.
|
|
40
|
+
def page_mode=(mode)
|
|
41
|
+
raise ArgumentError, "invalid page mode: #{mode}" unless PAGE_MODES.include?(mode)
|
|
42
|
+
|
|
43
|
+
document.catalog.value[:PageMode] = mode
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Set the /OpenAction destination or action.
|
|
47
|
+
# @param dest_or_action [Array, Hash, Pdfrb::Destination::Fit,
|
|
48
|
+
# Pdfrb::Model::PdfArray] the destination array or action dict.
|
|
49
|
+
def open_action=(dest_or_action)
|
|
50
|
+
document.catalog.value[:OpenAction] = dest_or_action
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get or set /ViewerPreferences as a keyword-hash.
|
|
54
|
+
def viewer_preferences(**opts)
|
|
55
|
+
return read_viewer_preferences if opts.empty?
|
|
56
|
+
|
|
57
|
+
vp = document.catalog.value[:ViewerPreferences]
|
|
58
|
+
vp ||= {}
|
|
59
|
+
opts.each do |key, value|
|
|
60
|
+
vp[key] = value
|
|
61
|
+
end
|
|
62
|
+
document.catalog.value[:ViewerPreferences] = vp
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Convenience: hide toolbar and menubar, fit window.
|
|
66
|
+
def presentation_mode!
|
|
67
|
+
viewer_preferences(
|
|
68
|
+
HideToolbar: true,
|
|
69
|
+
HideMenubar: true,
|
|
70
|
+
FitWindow: true,
|
|
71
|
+
CenterWindow: true,
|
|
72
|
+
DisplayDocTitle: true
|
|
73
|
+
)
|
|
74
|
+
self.page_mode = :FullScreen
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
def read_viewer_preferences
|
|
80
|
+
document.catalog.value[:ViewerPreferences] || {}
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|