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
data/lib/pdfrb/writer.rb
CHANGED
|
@@ -23,9 +23,42 @@ module Pdfrb
|
|
|
23
23
|
@io = io
|
|
24
24
|
@serializer = Serializer.new(
|
|
25
25
|
compress_streams: document.config["writer.compress_streams"],
|
|
26
|
-
compress_min_size: document.config["writer.compress_min_size"]
|
|
26
|
+
compress_min_size: document.config["writer.compress_min_size"],
|
|
27
|
+
**serializer_encrypter_opts
|
|
27
28
|
)
|
|
28
|
-
@xref_offsets = {}
|
|
29
|
+
@xref_offsets = {}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Build the encrypter option for the Serializer from the document's
|
|
33
|
+
# /Encrypt dict. If the document isn't encrypted, returns empty hash.
|
|
34
|
+
# The SecurityHandler's encrypt_data method becomes the Serializer's
|
|
35
|
+
# encrypter, which encrypts string/stream payloads per-object.
|
|
36
|
+
def serializer_encrypter_opts
|
|
37
|
+
# Use a pre-configured handler if the document provides one
|
|
38
|
+
# (e.g., set by the encryption CLI).
|
|
39
|
+
handler = document.config["encryption.handler"]
|
|
40
|
+
return { encrypter: handler } if handler
|
|
41
|
+
|
|
42
|
+
trailer = document.trailer
|
|
43
|
+
return {} unless trailer
|
|
44
|
+
|
|
45
|
+
encrypt_ref = trailer[:Encrypt]
|
|
46
|
+
return {} unless encrypt_ref
|
|
47
|
+
|
|
48
|
+
encrypt_dict = encrypt_ref.is_a?(Pdfrb::Model::Reference) ?
|
|
49
|
+
document.object(encrypt_ref) : encrypt_ref
|
|
50
|
+
return {} unless encrypt_dict
|
|
51
|
+
|
|
52
|
+
handler = Pdfrb::Encryption::StandardSecurityHandler.new(
|
|
53
|
+
Encrypt: encrypt_dict.value,
|
|
54
|
+
ID: trailer[:ID]
|
|
55
|
+
)
|
|
56
|
+
password = document.config["encryption.password"] || ""
|
|
57
|
+
handler.verify_user_password(password)
|
|
58
|
+
|
|
59
|
+
{ encrypter: handler }
|
|
60
|
+
rescue StandardError
|
|
61
|
+
{}
|
|
29
62
|
end
|
|
30
63
|
|
|
31
64
|
def self.write(document, io)
|
|
@@ -38,7 +71,7 @@ module Pdfrb
|
|
|
38
71
|
|
|
39
72
|
def write
|
|
40
73
|
@io.binmode
|
|
41
|
-
@io.truncate(0) if @io.
|
|
74
|
+
@io.truncate(0) if @io.is_a?(StringIO)
|
|
42
75
|
write_header
|
|
43
76
|
dispatch_before_write
|
|
44
77
|
|
|
@@ -81,7 +114,7 @@ module Pdfrb
|
|
|
81
114
|
@io << document.io.read
|
|
82
115
|
dispatch_before_write
|
|
83
116
|
# Emit only the modified objects.
|
|
84
|
-
document.
|
|
117
|
+
document.each_indirect_object do |obj|
|
|
85
118
|
next unless obj.indirect?
|
|
86
119
|
|
|
87
120
|
@xref_offsets[obj.oid] = @io.pos
|
|
@@ -106,13 +139,16 @@ module Pdfrb
|
|
|
106
139
|
max_oid = oids.max || 0
|
|
107
140
|
@io << "xref\n"
|
|
108
141
|
@io << "0 #{max_oid + 1}\n"
|
|
109
|
-
|
|
142
|
+
# Each entry must be EXACTLY 20 bytes per s7.5.4: 10-digit offset,
|
|
143
|
+
# 1 space, 5-digit gen, 1 space, 1-char type, 2-byte EOL (CR+LF).
|
|
144
|
+
# No trailing space before the EOL — that was the bug.
|
|
145
|
+
@io << format("%010d %05d f\r\n", 0, 65_535)
|
|
110
146
|
(1..max_oid).each do |oid|
|
|
111
147
|
offset = @xref_offsets[oid]
|
|
112
148
|
if offset
|
|
113
|
-
@io <<
|
|
149
|
+
@io << format("%010d %05d n\r\n", offset, 0)
|
|
114
150
|
else
|
|
115
|
-
@io <<
|
|
151
|
+
@io << format("%010d %05d f\r\n", 0, 0)
|
|
116
152
|
end
|
|
117
153
|
end
|
|
118
154
|
pos
|
|
@@ -132,25 +168,11 @@ module Pdfrb
|
|
|
132
168
|
w_type = 1
|
|
133
169
|
w_field2 = 3
|
|
134
170
|
w_field3 = 1
|
|
135
|
-
w_type + w_field2 + w_field3
|
|
136
|
-
|
|
137
|
-
data = +""
|
|
138
|
-
(0..max_oid).each do |oid|
|
|
139
|
-
if oid.zero?
|
|
140
|
-
data << encode_xref_entry(0, 0, 0, w_type, w_field2, w_field3)
|
|
141
|
-
elsif @xref_offsets.key?(oid)
|
|
142
|
-
data << encode_xref_entry(1, @xref_offsets[oid], 0,
|
|
143
|
-
w_type, w_field2, w_field3)
|
|
144
|
-
elsif packed.key?(oid)
|
|
145
|
-
objstm_oid, index = packed[oid]
|
|
146
|
-
data << encode_xref_entry(2, objstm_oid, index,
|
|
147
|
-
w_type, w_field2, w_field3)
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
171
|
|
|
172
|
+
data = build_xref_stream_data(max_oid, packed, w_type, w_field2, w_field3)
|
|
151
173
|
compressed = ::Zlib::Deflate.deflate(data)
|
|
152
174
|
|
|
153
|
-
xref_stream_oid = document.
|
|
175
|
+
xref_stream_oid = document.next_oid || (max_oid + 1)
|
|
154
176
|
stream_offset = @io.pos
|
|
155
177
|
header = "#{xref_stream_oid} 0 obj\n"
|
|
156
178
|
|
|
@@ -172,6 +194,33 @@ module Pdfrb
|
|
|
172
194
|
stream_offset
|
|
173
195
|
end
|
|
174
196
|
|
|
197
|
+
# Build the binary xref stream body. Always emits max_oid + 1
|
|
198
|
+
# entries (one per oid 0..max_oid) so the reader's per-oid index
|
|
199
|
+
# stays aligned. Gaps from dedup'd oids become free entries.
|
|
200
|
+
def build_xref_stream_data(max_oid, packed, w_type, w_field2, w_field3)
|
|
201
|
+
data = +""
|
|
202
|
+
(0..max_oid).each do |oid|
|
|
203
|
+
entry = xref_entry_for(oid, packed)
|
|
204
|
+
data << encode_xref_entry(entry[0], entry[1], entry[2],
|
|
205
|
+
w_type, w_field2, w_field3)
|
|
206
|
+
end
|
|
207
|
+
data
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Returns [type, field2, field3] for the xref entry of +oid+.
|
|
211
|
+
def xref_entry_for(oid, packed)
|
|
212
|
+
return [0, 0, 0] if oid.zero?
|
|
213
|
+
|
|
214
|
+
if @xref_offsets.key?(oid)
|
|
215
|
+
[1, @xref_offsets[oid], 0]
|
|
216
|
+
elsif packed.key?(oid)
|
|
217
|
+
objstm_oid, index = packed[oid]
|
|
218
|
+
[2, objstm_oid, index]
|
|
219
|
+
else
|
|
220
|
+
[0, 0, 0]
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
175
224
|
def write_xref_stream_trailer(xref_pos)
|
|
176
225
|
@io << "startxref\n#{xref_pos}\n%%EOF\n"
|
|
177
226
|
end
|
|
@@ -237,9 +286,9 @@ module Pdfrb
|
|
|
237
286
|
|
|
238
287
|
def write_trailer(xref_pos, prev: nil)
|
|
239
288
|
root = document.catalog
|
|
240
|
-
root_ref = root && root.
|
|
289
|
+
root_ref = root && root.is_a?(Pdfrb::Model::Object) && root.indirect? ?
|
|
241
290
|
Pdfrb::Model::Reference.new(root.oid, root.gen) : nil
|
|
242
|
-
size = [(@xref_offsets.keys.max || 0) + 1, document.
|
|
291
|
+
size = [(@xref_offsets.keys.max || 0) + 1, document.next_oid || 1].max
|
|
243
292
|
|
|
244
293
|
existing = document.trailer || {}
|
|
245
294
|
trailer_hash = {}
|
|
@@ -267,10 +316,12 @@ module Pdfrb
|
|
|
267
316
|
|
|
268
317
|
def dispatch_before_write
|
|
269
318
|
document.dispatch_message(:before_write)
|
|
319
|
+
compress_content_streams if document.config["writer.compress_streams"]
|
|
270
320
|
end
|
|
271
321
|
|
|
272
322
|
def version
|
|
273
|
-
document.version || DEFAULT_VERSION
|
|
323
|
+
v = document.version || DEFAULT_VERSION
|
|
324
|
+
detect_version_features(v)
|
|
274
325
|
end
|
|
275
326
|
|
|
276
327
|
def each_indirect_object
|
|
@@ -296,8 +347,47 @@ module Pdfrb
|
|
|
296
347
|
hash[k] = v
|
|
297
348
|
end
|
|
298
349
|
[(@xref_offsets.keys.max || 0) + 1,
|
|
299
|
-
document.
|
|
350
|
+
document.next_oid || 1].max
|
|
300
351
|
hash
|
|
301
352
|
end
|
|
353
|
+
|
|
354
|
+
def detect_version_features(current)
|
|
355
|
+
catalog = document.catalog
|
|
356
|
+
return current unless catalog
|
|
357
|
+
|
|
358
|
+
v = current
|
|
359
|
+
if (catalog.value[:AF] || catalog.value[:Collection]) && compare_versions(v, "2.0").negative?
|
|
360
|
+
v = "2.0"
|
|
361
|
+
end
|
|
362
|
+
if catalog.value[:OCProperties] && compare_versions(v, "1.5").negative?
|
|
363
|
+
v = "1.5"
|
|
364
|
+
end
|
|
365
|
+
document.version = v
|
|
366
|
+
v
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
def compare_versions(a, b)
|
|
370
|
+
aa = a.to_s.split(".").map(&:to_i)
|
|
371
|
+
bb = b.to_s.split(".").map(&:to_i)
|
|
372
|
+
(aa <=> bb) || 0
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
def compress_content_streams
|
|
376
|
+
require "zlib"
|
|
377
|
+
document.each_indirect_object do |obj|
|
|
378
|
+
next unless obj.is_a?(Pdfrb::Model::Cos::Stream)
|
|
379
|
+
next if obj.value[:Filter]
|
|
380
|
+
next unless obj.stream
|
|
381
|
+
next if obj.value[:Type] == :Metadata
|
|
382
|
+
|
|
383
|
+
min = document.config["writer.compress_min_size"] || 50
|
|
384
|
+
next if obj.stream.bytesize < min
|
|
385
|
+
|
|
386
|
+
compressed = ::Zlib::Deflate.deflate(obj.stream)
|
|
387
|
+
obj.stream = compressed
|
|
388
|
+
obj.value[:Filter] = :FlateDecode
|
|
389
|
+
obj.value[:Length] = compressed.bytesize
|
|
390
|
+
end
|
|
391
|
+
end
|
|
302
392
|
end
|
|
303
393
|
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin; require "lutaml/model"; rescue LoadError; end
|
|
4
|
+
|
|
5
|
+
module Pdfrb
|
|
6
|
+
module XMP
|
|
7
|
+
# XMP packet wrapper. An XMP packet is an XML document wrapped in
|
|
8
|
+
# processing instructions: <?xpacket begin?> ... <?xpacket end?>.
|
|
9
|
+
#
|
|
10
|
+
# The packet contains an RDF document with one Description element
|
|
11
|
+
# per schema. This class assembles the schemas into a single RDF
|
|
12
|
+
# Description and wraps it in the packet PI.
|
|
13
|
+
class Packet
|
|
14
|
+
XMP_BEGIN = "<?xpacket begin=\"\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n"
|
|
15
|
+
XMP_END = "<?xpacket end=\"w\"?>\n"
|
|
16
|
+
|
|
17
|
+
attr_reader :dc, :pdf, :xmp, :rights
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
@dc = Schemas::DublinCore.new
|
|
21
|
+
@pdf = Schemas::PDF.new
|
|
22
|
+
@xmp = Schemas::XMPBasic.new
|
|
23
|
+
@rights = Schemas::XMPRights.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def title=(value); @dc.title = Array(value); end
|
|
27
|
+
def title; @dc.title.first; end
|
|
28
|
+
def creator=(value); @dc.creator = Array(value); end
|
|
29
|
+
def creator; @dc.creator.first; end
|
|
30
|
+
|
|
31
|
+
def author=(value); @dc.creator = Array(value); end
|
|
32
|
+
def author; @dc.creator.first; end
|
|
33
|
+
def description=(value); @dc.description = Array(value); end
|
|
34
|
+
def description; @dc.description.first; end
|
|
35
|
+
def subject=(value); @dc.subject = Array(value); end
|
|
36
|
+
def subject; @dc.subject; end
|
|
37
|
+
|
|
38
|
+
def keywords=(value); @pdf.keywords = value; end
|
|
39
|
+
def keywords; @pdf.keywords; end
|
|
40
|
+
def producer=(value); @pdf.producer = value; end
|
|
41
|
+
def producer; @pdf.producer; end
|
|
42
|
+
|
|
43
|
+
def creator_tool=(value); @xmp.creator_tool = value; end
|
|
44
|
+
def creator_tool; @xmp.creator_tool; end
|
|
45
|
+
|
|
46
|
+
def to_xmp
|
|
47
|
+
XMP_BEGIN + rdf_body + XMP_END
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def rdf_body
|
|
53
|
+
lines = [
|
|
54
|
+
'<x:xmpmeta xmlns:x="adobe:ns:meta/">',
|
|
55
|
+
'<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">',
|
|
56
|
+
'<rdf:Description rdf:about=""',
|
|
57
|
+
' xmlns:dc="http://purl.org/dc/elements/1.1/"',
|
|
58
|
+
' xmlns:pdf="http://ns.adobe.com/pdf/1.3/"',
|
|
59
|
+
' xmlns:xmp="http://ns.adobe.com/xap/1.0/">',
|
|
60
|
+
]
|
|
61
|
+
lines += schema_lines
|
|
62
|
+
lines << "</rdf:Description>"
|
|
63
|
+
lines << "</rdf:RDF>"
|
|
64
|
+
lines << "</x:xmpmeta>"
|
|
65
|
+
"#{lines.join("\n")}\n"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def schema_lines
|
|
69
|
+
parts = []
|
|
70
|
+
parts += dc_lines if has_dc?
|
|
71
|
+
parts += pdf_lines if has_pdf?
|
|
72
|
+
parts += xmp_lines if has_xmp?
|
|
73
|
+
parts
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def has_dc?
|
|
77
|
+
(@dc.title && !@dc.title.empty?) ||
|
|
78
|
+
(@dc.creator && !@dc.creator.empty?) ||
|
|
79
|
+
(@dc.description && !@dc.description.empty?) ||
|
|
80
|
+
(@dc.subject && !@dc.subject.empty?)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def has_pdf?
|
|
84
|
+
@pdf.keywords || @pdf.producer || @pdf.trapped
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def has_xmp?
|
|
88
|
+
@xmp.creator_tool || @xmp.create_date || @xmp.modify_date
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def dc_lines
|
|
92
|
+
lines = (@dc.title || []).map { |t| " <dc:title><rdf:Alt><rdf:li xml:lang=\"x-default\">#{escape(t)}</rdf:li></rdf:Alt></dc:title>" }
|
|
93
|
+
(@dc.creator || []).each { |c| lines << " <dc:creator><rdf:Seq><rdf:li>#{escape(c)}</rdf:li></rdf:Seq></dc:creator>" }
|
|
94
|
+
(@dc.description || []).each { |d| lines << " <dc:description><rdf:Alt><rdf:li xml:lang=\"x-default\">#{escape(d)}</rdf:li></rdf:Alt></dc:description>" }
|
|
95
|
+
(@dc.subject || []).each { |s| lines << " <dc:subject><rdf:Bag><rdf:li>#{escape(s)}</rdf:li></rdf:Bag></dc:subject>" }
|
|
96
|
+
lines
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def pdf_lines
|
|
100
|
+
lines = []
|
|
101
|
+
lines << " <pdf:Keywords>#{escape(@pdf.keywords)}</pdf:Keywords>" if @pdf.keywords
|
|
102
|
+
lines << " <pdf:Producer>#{escape(@pdf.producer)}</pdf:Producer>" if @pdf.producer
|
|
103
|
+
lines
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def xmp_lines
|
|
107
|
+
lines = []
|
|
108
|
+
lines << " <xmp:CreatorTool>#{escape(@xmp.creator_tool)}</xmp:CreatorTool>" if @xmp.creator_tool
|
|
109
|
+
lines << " <xmp:CreateDate>#{@xmp.create_date}</xmp:CreateDate>" if @xmp.create_date
|
|
110
|
+
lines << " <xmp:ModifyDate>#{@xmp.modify_date}</xmp:ModifyDate>" if @xmp.modify_date
|
|
111
|
+
lines
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def escape(str)
|
|
115
|
+
str.to_s
|
|
116
|
+
.gsub("&", "&")
|
|
117
|
+
.gsub("<", "<")
|
|
118
|
+
.gsub(">", ">")
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
begin; require "lutaml/model"; rescue LoadError; end
|
|
4
|
+
|
|
5
|
+
module Pdfrb
|
|
6
|
+
module XMP
|
|
7
|
+
module Schemas
|
|
8
|
+
# Namespace definitions for XMP schemas.
|
|
9
|
+
class DublinCoreNS < Lutaml::Xml::Namespace
|
|
10
|
+
uri "http://purl.org/dc/elements/1.1/"
|
|
11
|
+
prefix_default "dc"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class PdfNS < Lutaml::Xml::Namespace
|
|
15
|
+
uri "http://ns.adobe.com/pdf/1.3/"
|
|
16
|
+
prefix_default "pdf"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
class XmpNS < Lutaml::Xml::Namespace
|
|
20
|
+
uri "http://ns.adobe.com/xap/1.0/"
|
|
21
|
+
prefix_default "xmp"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class XmpRightsNS < Lutaml::Xml::Namespace
|
|
25
|
+
uri "http://ns.adobe.com/xap/1.0/rights/"
|
|
26
|
+
prefix_default "xmpRights"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Dublin Core (dc:) — basic descriptive metadata.
|
|
30
|
+
class DublinCore < Lutaml::Model::Serializable
|
|
31
|
+
attribute :title, :string, collection: true
|
|
32
|
+
attribute :creator, :string, collection: true
|
|
33
|
+
attribute :description, :string, collection: true
|
|
34
|
+
attribute :subject, :string, collection: true
|
|
35
|
+
attribute :identifier, :string, collection: true
|
|
36
|
+
attribute :language, :string, collection: true
|
|
37
|
+
|
|
38
|
+
xml do
|
|
39
|
+
root "dc"
|
|
40
|
+
namespace DublinCoreNS
|
|
41
|
+
map_element "title", to: :title
|
|
42
|
+
map_element "creator", to: :creator
|
|
43
|
+
map_element "description", to: :description
|
|
44
|
+
map_element "subject", to: :subject
|
|
45
|
+
map_element "identifier", to: :identifier
|
|
46
|
+
map_element "language", to: :language
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# PDF (pdf:) — PDF-specific metadata.
|
|
51
|
+
class PDF < Lutaml::Model::Serializable
|
|
52
|
+
attribute :keywords, :string
|
|
53
|
+
attribute :producer, :string
|
|
54
|
+
attribute :trapped, :string
|
|
55
|
+
|
|
56
|
+
xml do
|
|
57
|
+
root "pdf"
|
|
58
|
+
namespace PdfNS
|
|
59
|
+
map_element "Keywords", to: :keywords
|
|
60
|
+
map_element "Producer", to: :producer
|
|
61
|
+
map_element "Trapped", to: :trapped
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# XMP basic (xmp:) — document lifecycle metadata.
|
|
66
|
+
class XMPBasic < Lutaml::Model::Serializable
|
|
67
|
+
attribute :creator_tool, :string
|
|
68
|
+
attribute :create_date, :string
|
|
69
|
+
attribute :modify_date, :string
|
|
70
|
+
attribute :metadata_date, :string
|
|
71
|
+
|
|
72
|
+
xml do
|
|
73
|
+
root "xmp"
|
|
74
|
+
namespace XmpNS
|
|
75
|
+
map_element "CreatorTool", to: :creator_tool
|
|
76
|
+
map_element "CreateDate", to: :create_date
|
|
77
|
+
map_element "ModifyDate", to: :modify_date
|
|
78
|
+
map_element "MetadataDate", to: :metadata_date
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# XMP Rights (xmpRights:) — rights management metadata.
|
|
83
|
+
class XMPRights < Lutaml::Model::Serializable
|
|
84
|
+
attribute :marked, :boolean
|
|
85
|
+
attribute :web_statement, :string
|
|
86
|
+
|
|
87
|
+
xml do
|
|
88
|
+
root "xmpRights"
|
|
89
|
+
namespace XmpRightsNS
|
|
90
|
+
map_element "Marked", to: :marked
|
|
91
|
+
map_element "WebStatement", to: :web_statement
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/pdfrb/xmp.rb
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module XMP
|
|
5
|
+
autoload :Packet, "pdfrb/xmp/packet"
|
|
6
|
+
autoload :Schemas, "pdfrb/xmp/schemas"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Pdfrb::Document.prepend(Module.new do
|
|
11
|
+
def write(path = nil, io: nil)
|
|
12
|
+
sync_xmp_metadata! unless self.io
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def sync_xmp_metadata!
|
|
19
|
+
info = trailer&.[](:Info)
|
|
20
|
+
return unless info
|
|
21
|
+
|
|
22
|
+
info_obj = object(info)
|
|
23
|
+
return unless info_obj
|
|
24
|
+
|
|
25
|
+
title = info_obj.value[:Title]
|
|
26
|
+
return unless title
|
|
27
|
+
|
|
28
|
+
packet = begin
|
|
29
|
+
xmp
|
|
30
|
+
rescue StandardError
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
return unless packet
|
|
34
|
+
|
|
35
|
+
xmp_data = packet.to_xmp
|
|
36
|
+
stream = add(
|
|
37
|
+
{ Type: :Metadata, Subtype: :XML, Length: xmp_data.bytesize },
|
|
38
|
+
type: Pdfrb::Model::Cos::Stream
|
|
39
|
+
)
|
|
40
|
+
stream.stream = xmp_data
|
|
41
|
+
catalog.value[:Metadata] =
|
|
42
|
+
Pdfrb::Model::Reference.new(stream.oid, stream.gen)
|
|
43
|
+
end
|
|
44
|
+
end)
|
data/lib/pdfrb/xref_section.rb
CHANGED
data/lib/pdfrb.rb
CHANGED
|
@@ -1,35 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Pdfrb — pure-Ruby PDF library.
|
|
4
|
-
#
|
|
5
|
-
# Two-direction contract:
|
|
6
|
-
# * "PDF file <=> Model" — parse PDF bytes into a typed Model, serialize
|
|
7
|
-
# a Model back to PDF bytes. Round-trip is the correctness backbone.
|
|
8
|
-
# * "API Builder Input => Model" — Document / Canvas build a typed
|
|
9
|
-
# Model from user intent, which is then serialized.
|
|
10
|
-
#
|
|
11
|
-
# Pdfrb is deliberately scoped to the PDF byte format. Layout concerns
|
|
12
|
-
# (page templates, flows, line breaking, tables, etc.) live in the
|
|
13
|
-
# sibling `arroolio` gem.
|
|
14
|
-
#
|
|
15
|
-
# The PDF object model is sourced directly from the vendored Arlington
|
|
16
|
-
# PDF Model TSVs (data/pdfrb/arlington/*.tsv). Field metadata, version
|
|
17
|
-
# predicates, and validators stay aligned with ISO 32000-2:2020 by data,
|
|
18
|
-
# not by hand-coded mimicry.
|
|
19
|
-
#
|
|
20
|
-
# Layering (mirrors the sibling postscript gem):
|
|
21
|
-
# Source — bytes → tokens → COS graph (read direction)
|
|
22
|
-
# Model — typed domain model (COS values + Type::* semantics)
|
|
23
|
-
# Arlington — TSV loader + predicate evaluator (drives Model field defs)
|
|
24
|
-
# Filter — stream filter pipeline (Flate, ASCII-85, LZW, ...)
|
|
25
|
-
# Content — content-stream operators + Canvas drawing API
|
|
26
|
-
# Serializer — Model → bytes
|
|
27
|
-
# Writer — Document → file (xref + trailer assembly)
|
|
28
|
-
# Document — top-level facade
|
|
29
3
|
module Pdfrb
|
|
30
4
|
autoload :VERSION, "pdfrb/version"
|
|
31
5
|
|
|
32
|
-
# Errors — every failure mode in the gem subclasses Pdfrb::Error.
|
|
33
6
|
autoload :Error, "pdfrb/error"
|
|
34
7
|
autoload :ParseError, "pdfrb/error"
|
|
35
8
|
autoload :LexError, "pdfrb/error"
|
|
@@ -42,13 +15,10 @@ module Pdfrb
|
|
|
42
15
|
autoload :ValidationError, "pdfrb/error"
|
|
43
16
|
autoload :ObjectReferenceError, "pdfrb/error"
|
|
44
17
|
|
|
45
|
-
# Cross-cutting helpers.
|
|
46
18
|
autoload :Configuration, "pdfrb/configuration"
|
|
47
19
|
autoload :DataDir, "pdfrb/data_dir"
|
|
48
20
|
autoload :PdfConstants, "pdfrb/pdf_constants"
|
|
49
21
|
|
|
50
|
-
# Sub-namespaces. Each lives in its own file which holds the autoloads
|
|
51
|
-
# for that namespace's children (the "immediate parent" rule).
|
|
52
22
|
autoload :Source, "pdfrb/source"
|
|
53
23
|
autoload :Model, "pdfrb/model"
|
|
54
24
|
autoload :Arlington, "pdfrb/arlington"
|
|
@@ -57,32 +27,22 @@ module Pdfrb
|
|
|
57
27
|
autoload :Encryption, "pdfrb/encryption"
|
|
58
28
|
autoload :DigitalSignature, "pdfrb/digital_signature"
|
|
59
29
|
|
|
60
|
-
# Eager-load Type::* subclasses so they self-register in the
|
|
61
|
-
# /Type-symbol type_map before any wrap call happens. Without
|
|
62
|
-
# this, the first read of a Catalog wouldn't upgrade to
|
|
63
|
-
# Type::Catalog (because the constant hadn't been autoloaded yet
|
|
64
|
-
# and therefore hadn't called register_type).
|
|
65
|
-
require "pdfrb/model/type/file_trailer"
|
|
66
|
-
require "pdfrb/model/type/catalog"
|
|
67
|
-
require "pdfrb/model/type/info"
|
|
68
|
-
require "pdfrb/model/type/page_tree_node"
|
|
69
|
-
require "pdfrb/model/type/page"
|
|
70
|
-
require "pdfrb/model/type/resources"
|
|
71
|
-
require "pdfrb/model/type/metadata"
|
|
72
|
-
require "pdfrb/model/type/object_stream"
|
|
73
|
-
require "pdfrb/model/type/xref_stream"
|
|
74
|
-
require "pdfrb/model/type/graphics_state_parameter"
|
|
75
|
-
require "pdfrb/model/type/optional_content_group"
|
|
76
|
-
require "pdfrb/model/type/struct_tree_root"
|
|
77
|
-
require "pdfrb/model/type/font_type1"
|
|
78
|
-
require "pdfrb/model/type/annotation"
|
|
79
|
-
require "pdfrb/model/type/action"
|
|
80
30
|
autoload :Font, "pdfrb/font"
|
|
81
31
|
autoload :FontLoader, "pdfrb/font_loader"
|
|
32
|
+
autoload :FontResolver, "pdfrb/font_resolver"
|
|
82
33
|
autoload :ImageLoader, "pdfrb/image_loader"
|
|
34
|
+
autoload :Image, "pdfrb/image"
|
|
83
35
|
autoload :Task, "pdfrb/task"
|
|
36
|
+
autoload :Color, "pdfrb/color"
|
|
37
|
+
autoload :Annotation, "pdfrb/annotation"
|
|
38
|
+
autoload :Appearance, "pdfrb/appearance"
|
|
39
|
+
autoload :Conformance, "pdfrb/conformance"
|
|
40
|
+
autoload :Validator, "pdfrb/validator"
|
|
41
|
+
autoload :XMP, "pdfrb/xmp"
|
|
42
|
+
autoload :Destination, "pdfrb/destination"
|
|
43
|
+
autoload :Linearization, "pdfrb/linearization"
|
|
44
|
+
autoload :Action, "pdfrb/action"
|
|
84
45
|
|
|
85
|
-
# Top-level orchestrators.
|
|
86
46
|
autoload :Serializer, "pdfrb/serializer"
|
|
87
47
|
autoload :Writer, "pdfrb/writer"
|
|
88
48
|
autoload :Importer, "pdfrb/importer"
|
|
@@ -91,7 +51,19 @@ module Pdfrb
|
|
|
91
51
|
autoload :XrefSection, "pdfrb/xref_section"
|
|
92
52
|
autoload :Document, "pdfrb/document"
|
|
93
53
|
|
|
94
|
-
|
|
95
|
-
|
|
54
|
+
autoload :Layout, "pdfrb/layout"
|
|
55
|
+
autoload :Composer, "pdfrb/composer"
|
|
56
|
+
autoload :Compare, "pdfrb/compare"
|
|
57
|
+
autoload :TestUtils, "pdfrb/test_utils"
|
|
96
58
|
autoload :CLI, "pdfrb/cli"
|
|
59
|
+
|
|
60
|
+
require "logger"
|
|
61
|
+
|
|
62
|
+
def self.logger
|
|
63
|
+
@logger ||= Logger.new($stderr, level: Logger::WARN)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.logger=(log)
|
|
67
|
+
@logger = log
|
|
68
|
+
end
|
|
97
69
|
end
|
data/pdfrb.gemspec
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/pdfrb/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "pdfrb"
|
|
7
|
+
spec.version = Pdfrb::VERSION
|
|
8
|
+
spec.authors = ["Ribose Inc."]
|
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Pure-Ruby PDF parser, Arlington-model-driven domain model, and serializer"
|
|
12
|
+
spec.description = <<~HEREDOC
|
|
13
|
+
Pdfrb is a pure-Ruby PDF library: a byte-level reader, an
|
|
14
|
+
Arlington-model-driven typed domain model, and a serializer. The
|
|
15
|
+
PDF object model is sourced directly from the vendored Arlington
|
|
16
|
+
PDF Model TSVs (machine-readable ISO 32000-2:2020), so field
|
|
17
|
+
metadata, version predicates, and validators stay aligned with
|
|
18
|
+
the spec by data, not by hand-coded mimicry.
|
|
19
|
+
|
|
20
|
+
Two-direction contract: "PDF file <=> Model" and "API Builder
|
|
21
|
+
Input => Model". Mirrors the layered design of the sibling
|
|
22
|
+
postscript gem.
|
|
23
|
+
HEREDOC
|
|
24
|
+
|
|
25
|
+
spec.homepage = "https://github.com/claricle/pdfrb"
|
|
26
|
+
spec.license = "BSD-2-Clause"
|
|
27
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
28
|
+
|
|
29
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
30
|
+
spec.metadata["source_code_uri"] = "https://github.com/claricle/pdfrb"
|
|
31
|
+
spec.metadata["changelog_uri"] = "https://github.com/claricle/pdfrb/blob/main/CHANGELOG.md"
|
|
32
|
+
spec.metadata["bug_tracker_uri"] = "https://github.com/claricle/pdfrb/issues"
|
|
33
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
34
|
+
|
|
35
|
+
spec.files = Dir.chdir(__dir__) do
|
|
36
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
37
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
spec.bindir = "exe"
|
|
41
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
42
|
+
spec.require_paths = ["lib"]
|
|
43
|
+
|
|
44
|
+
spec.add_dependency "thor"
|
|
45
|
+
end
|