pdfrb 0.3.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +51 -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 +61 -0
- data/data/pdfrb/afm/Courier-Bold.afm +342 -342
- data/data/pdfrb/afm/Courier-BoldOblique.afm +342 -342
- data/data/pdfrb/afm/Courier-Oblique.afm +342 -342
- data/data/pdfrb/afm/Courier.afm +342 -342
- data/data/pdfrb/afm/Helvetica-Bold.afm +2827 -2827
- data/data/pdfrb/afm/Helvetica-BoldOblique.afm +2827 -2827
- data/data/pdfrb/afm/Helvetica-Oblique.afm +3051 -3051
- data/data/pdfrb/afm/Helvetica.afm +3051 -3051
- data/data/pdfrb/afm/Symbol.afm +213 -213
- data/data/pdfrb/afm/Times-Bold.afm +2588 -2588
- data/data/pdfrb/afm/Times-BoldItalic.afm +2384 -2384
- data/data/pdfrb/afm/Times-Italic.afm +2667 -2667
- data/data/pdfrb/afm/Times-Roman.afm +2419 -2419
- data/data/pdfrb/afm/ZapfDingbats.afm +225 -225
- 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 +354 -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/inline_image.rb +53 -0
- data/lib/pdfrb/content/operators.rb +22 -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 +82 -251
- 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_piece_info.rb +58 -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 +289 -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/regenerate_appearances.rb +98 -0
- data/lib/pdfrb/task.rb +4 -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 +319 -4
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
module ColorSpace
|
|
6
|
+
REGISTRY = {} # rubocop:disable Style/MutableConstant
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
def register(name, klass)
|
|
10
|
+
REGISTRY[name.to_sym] = klass
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def resolve(name, _document = nil)
|
|
14
|
+
REGISTRY[name.to_sym]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def families
|
|
18
|
+
REGISTRY.keys
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class DeviceGray
|
|
23
|
+
def self.family; :DeviceGray; end
|
|
24
|
+
def self.components; 1; end
|
|
25
|
+
def self.default; [0.0]; end
|
|
26
|
+
end
|
|
27
|
+
register :DeviceGray, DeviceGray
|
|
28
|
+
|
|
29
|
+
class DeviceRGB
|
|
30
|
+
def self.family; :DeviceRGB; end
|
|
31
|
+
def self.components; 3; end
|
|
32
|
+
def self.default; [0.0, 0.0, 0.0]; end
|
|
33
|
+
end
|
|
34
|
+
register :DeviceRGB, DeviceRGB
|
|
35
|
+
|
|
36
|
+
class DeviceCMYK
|
|
37
|
+
def self.family; :DeviceCMYK; end
|
|
38
|
+
def self.components; 4; end
|
|
39
|
+
def self.default; [0.0, 0.0, 0.0, 1.0]; end
|
|
40
|
+
end
|
|
41
|
+
register :DeviceCMYK, DeviceCMYK
|
|
42
|
+
|
|
43
|
+
class CalGray
|
|
44
|
+
attr_reader :white_point, :gamma
|
|
45
|
+
|
|
46
|
+
def initialize(white_point:, gamma: 1.0)
|
|
47
|
+
@white_point = white_point
|
|
48
|
+
@gamma = gamma
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def family; :CalGray; end
|
|
52
|
+
def components; 1; end
|
|
53
|
+
end
|
|
54
|
+
register :CalGray, CalGray
|
|
55
|
+
|
|
56
|
+
class CalRGB
|
|
57
|
+
attr_reader :white_point, :black_point, :gamma
|
|
58
|
+
|
|
59
|
+
def initialize(white_point:, black_point: [0, 0, 0], gamma: [1, 1, 1])
|
|
60
|
+
@white_point = white_point
|
|
61
|
+
@black_point = black_point
|
|
62
|
+
@gamma = gamma
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def family; :CalRGB; end
|
|
66
|
+
def components; 3; end
|
|
67
|
+
end
|
|
68
|
+
register :CalRGB, CalRGB
|
|
69
|
+
|
|
70
|
+
class Lab
|
|
71
|
+
attr_reader :white_point, :black_point, :range
|
|
72
|
+
|
|
73
|
+
def initialize(white_point:, black_point: [0, 0, 0], range: [-100, 100, -100, 100])
|
|
74
|
+
@white_point = white_point
|
|
75
|
+
@black_point = black_point
|
|
76
|
+
@range = range
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def family; :Lab; end
|
|
80
|
+
def components; 3; end
|
|
81
|
+
end
|
|
82
|
+
register :Lab, Lab
|
|
83
|
+
|
|
84
|
+
class ICCBased
|
|
85
|
+
attr_reader :stream_ref, :alternate, :range, :n
|
|
86
|
+
|
|
87
|
+
def initialize(stream_ref:, n:, alternate: nil, range: nil)
|
|
88
|
+
@stream_ref = stream_ref
|
|
89
|
+
@n = n
|
|
90
|
+
@alternate = alternate
|
|
91
|
+
@range = range
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def family; :ICCBased; end
|
|
95
|
+
def components; @n; end
|
|
96
|
+
end
|
|
97
|
+
register :ICCBased, ICCBased
|
|
98
|
+
|
|
99
|
+
class Indexed
|
|
100
|
+
attr_reader :base, :hival, :lookup
|
|
101
|
+
|
|
102
|
+
def initialize(base:, hival:, lookup:)
|
|
103
|
+
@base = base
|
|
104
|
+
@hival = hival
|
|
105
|
+
@lookup = lookup
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def family; :Indexed; end
|
|
109
|
+
def components; 1; end
|
|
110
|
+
end
|
|
111
|
+
register :Indexed, Indexed
|
|
112
|
+
|
|
113
|
+
class Separation
|
|
114
|
+
attr_reader :name, :alternate_space, :tint_transform
|
|
115
|
+
|
|
116
|
+
def initialize(name:, alternate_space:, tint_transform:)
|
|
117
|
+
@name = name
|
|
118
|
+
@alternate_space = alternate_space
|
|
119
|
+
@tint_transform = tint_transform
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def family; :Separation; end
|
|
123
|
+
def components; 1; end
|
|
124
|
+
end
|
|
125
|
+
register :Separation, Separation
|
|
126
|
+
|
|
127
|
+
class DeviceN
|
|
128
|
+
attr_reader :names, :alternate_space, :tint_transform
|
|
129
|
+
|
|
130
|
+
def initialize(names:, alternate_space:, tint_transform:)
|
|
131
|
+
@names = names
|
|
132
|
+
@alternate_space = alternate_space
|
|
133
|
+
@tint_transform = tint_transform
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def family; :DeviceN; end
|
|
137
|
+
|
|
138
|
+
def components
|
|
139
|
+
(@names || []).length
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
register :DeviceN, DeviceN
|
|
143
|
+
|
|
144
|
+
class Pattern
|
|
145
|
+
attr_reader :base_space
|
|
146
|
+
|
|
147
|
+
def initialize(base_space: nil)
|
|
148
|
+
@base_space = base_space
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def family; :Pattern; end
|
|
152
|
+
def components; 0; end
|
|
153
|
+
end
|
|
154
|
+
register :Pattern, Pattern
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
|
|
5
|
+
module Pdfrb
|
|
6
|
+
module Content
|
|
7
|
+
# Detects hidden / transparent text in content streams. Hidden text
|
|
8
|
+
# is text rendered with Tr=3 (invisible) or with alpha=0 (fully
|
|
9
|
+
# transparent). PDF/A and PDF/UA require such text to be tagged as
|
|
10
|
+
# /Artifact or wrapped in a structure element.
|
|
11
|
+
#
|
|
12
|
+
# Inspired by mn2pdf's PDFHiddenTextStripper. Walks content streams
|
|
13
|
+
# via the Content::Parser, tracking graphics state changes.
|
|
14
|
+
class HiddenTextDetector
|
|
15
|
+
HiddenItem = Struct.new(:text, :reason, :page, keyword_init: true) do
|
|
16
|
+
def hidden?
|
|
17
|
+
!reason.nil?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
attr_reader :document
|
|
22
|
+
|
|
23
|
+
def initialize(document)
|
|
24
|
+
@document = document
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Walk all content streams. Returns HiddenItem objects for each
|
|
28
|
+
# text-showing operation. Items with a nil reason are visible.
|
|
29
|
+
def detect
|
|
30
|
+
items = []
|
|
31
|
+
@document.each_indirect_object do |obj|
|
|
32
|
+
next unless content_stream?(obj)
|
|
33
|
+
|
|
34
|
+
page = find_page(obj)
|
|
35
|
+
detect_in_stream(obj, page) { |item| items << item }
|
|
36
|
+
end
|
|
37
|
+
items
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Returns only the hidden text items (rendering_mode_3 or alpha=0).
|
|
41
|
+
def hidden_only
|
|
42
|
+
detect.select(&:hidden?)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def content_stream?(obj)
|
|
48
|
+
return false unless obj.is_a?(Pdfrb::Model::Cos::Stream)
|
|
49
|
+
return true if obj.value[:Type] == :Page
|
|
50
|
+
|
|
51
|
+
subtype = obj.value[:Subtype]
|
|
52
|
+
return false if subtype == :Image
|
|
53
|
+
|
|
54
|
+
true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def find_page(stream_obj)
|
|
58
|
+
@document.each_indirect_object do |obj|
|
|
59
|
+
next unless obj.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
60
|
+
next unless obj[:Type] == :Page
|
|
61
|
+
|
|
62
|
+
contents = obj[:Contents]
|
|
63
|
+
next unless contents
|
|
64
|
+
|
|
65
|
+
list = if contents.is_a?(Pdfrb::Model::PdfArray)
|
|
66
|
+
contents.value
|
|
67
|
+
else
|
|
68
|
+
contents.is_a?(::Array) ? contents : [contents]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
return obj if list.any? do |c|
|
|
72
|
+
c_obj = c.is_a?(Pdfrb::Model::Reference) ? @document.object(c) : c
|
|
73
|
+
c_obj == stream_obj
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
nil
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def detect_in_stream(stream_obj, page, &)
|
|
80
|
+
bytes = stream_obj.stream
|
|
81
|
+
return unless bytes && !bytes.empty?
|
|
82
|
+
|
|
83
|
+
io = StringIO.new(bytes.b)
|
|
84
|
+
tokenizer = Pdfrb::Source::Tokenizer.new(io)
|
|
85
|
+
parser = Content::Parser.new(tokenizer)
|
|
86
|
+
collector = Collector.new(page)
|
|
87
|
+
|
|
88
|
+
parser.each_invocation do |op_class, operands|
|
|
89
|
+
op_name = op_class.name
|
|
90
|
+
case op_name
|
|
91
|
+
when "Tr"
|
|
92
|
+
collector.text_rendering_mode = operands.first.to_i if operands.first
|
|
93
|
+
when "ca"
|
|
94
|
+
collector.stroke_alpha = operands.first.to_f if operands.first
|
|
95
|
+
when "CA"
|
|
96
|
+
collector.non_stroke_alpha = operands.first.to_f if operands.first
|
|
97
|
+
when "Tj"
|
|
98
|
+
collector.show_text(operands.first)
|
|
99
|
+
when "TJ"
|
|
100
|
+
collector.show_text_array(operands.first)
|
|
101
|
+
when "'", "\""
|
|
102
|
+
collector.move_to_next_line
|
|
103
|
+
collector.show_text(operands.first) if operands.first
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
collector.items.each(&)
|
|
108
|
+
rescue StandardError
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Internal: collects text-show operations with their visibility state.
|
|
113
|
+
class Collector
|
|
114
|
+
attr_reader :items
|
|
115
|
+
|
|
116
|
+
def initialize(page)
|
|
117
|
+
@items = []
|
|
118
|
+
@page = page
|
|
119
|
+
@text_rendering_mode = 0
|
|
120
|
+
@non_stroke_alpha = 1.0
|
|
121
|
+
@stroke_alpha = 1.0
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def text_rendering_mode=(value)
|
|
125
|
+
@text_rendering_mode = value
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def non_stroke_alpha=(value)
|
|
129
|
+
@non_stroke_alpha = value
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def stroke_alpha=(value)
|
|
133
|
+
@stroke_alpha = value
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def show_text(text)
|
|
137
|
+
return if text.nil?
|
|
138
|
+
|
|
139
|
+
reason = current_reason
|
|
140
|
+
@items << HiddenItem.new(text: text.to_s, reason: reason, page: @page)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def show_text_array(items)
|
|
144
|
+
return unless items.is_a?(::Array)
|
|
145
|
+
|
|
146
|
+
items.each do |item|
|
|
147
|
+
if item.is_a?(::String)
|
|
148
|
+
show_text(item)
|
|
149
|
+
end
|
|
150
|
+
# Numeric items are positioning values; ignore them
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def move_to_next_line; end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def current_reason
|
|
159
|
+
return :rendering_mode_invisible if @text_rendering_mode == 3
|
|
160
|
+
return :alpha_zero_hidden if @non_stroke_alpha.to_f == 0.0 || @stroke_alpha.to_f == 0.0
|
|
161
|
+
|
|
162
|
+
nil
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
@@ -20,12 +20,32 @@ module Pdfrb
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def [](name)
|
|
23
|
-
|
|
23
|
+
key = name.to_s
|
|
24
|
+
result = @registry[key]
|
|
25
|
+
return result if result
|
|
26
|
+
|
|
27
|
+
# Lazy-load on miss: trigger eager_load! which populates
|
|
28
|
+
# the registry, then retry.
|
|
29
|
+
eager_load! unless @eager_loaded
|
|
30
|
+
@registry[key]
|
|
24
31
|
end
|
|
25
32
|
|
|
26
33
|
def names
|
|
27
34
|
@registry.keys
|
|
28
35
|
end
|
|
36
|
+
|
|
37
|
+
# Force-load all operator implementations so register calls
|
|
38
|
+
# fire and populate the registry. Idempotent.
|
|
39
|
+
def eager_load!
|
|
40
|
+
return if @eager_loaded
|
|
41
|
+
|
|
42
|
+
Pdfrb::Content::Operators.constants.each do |c|
|
|
43
|
+
Pdfrb::Content::Operators.const_get(c)
|
|
44
|
+
rescue NameError
|
|
45
|
+
# Skip modules that don't resolve.
|
|
46
|
+
end
|
|
47
|
+
@eager_loaded = true
|
|
48
|
+
end
|
|
29
49
|
end
|
|
30
50
|
|
|
31
51
|
# Base class. Subclasses override +name+ and optionally
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
module Operator
|
|
6
|
+
# Clipping path operators (s8.5.4). W and W* modify the current
|
|
7
|
+
# clipping path by intersecting it with the current path. The
|
|
8
|
+
# clipping path takes effect when the next painting operator or
|
|
9
|
+
# `n` (end path) is executed.
|
|
10
|
+
|
|
11
|
+
# `W` — modify clipping path using nonzero winding rule.
|
|
12
|
+
class ClipNonZero < NoArg
|
|
13
|
+
def self.name; "W"; end
|
|
14
|
+
register
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# `W*` — modify clipping path using even-odd rule.
|
|
18
|
+
class ClipEvenOdd < NoArg
|
|
19
|
+
def self.name; "W*"; end
|
|
20
|
+
register
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# `Do` — invoke an XObject (Image or Form) by resource name.
|
|
24
|
+
class InvokeXObject < Base
|
|
25
|
+
class << self
|
|
26
|
+
def name; "Do"; end
|
|
27
|
+
|
|
28
|
+
def serialize(_serializer, name)
|
|
29
|
+
"/#{name} Do\n"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
register
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -73,6 +73,21 @@ module Pdfrb
|
|
|
73
73
|
end
|
|
74
74
|
register
|
|
75
75
|
end
|
|
76
|
+
class NonStrokeAlpha < Base
|
|
77
|
+
def self.name; "ca"; end
|
|
78
|
+
def self.invoke(processor, alpha)
|
|
79
|
+
processor.update_graphics_state(non_stroke_alpha: alpha.to_f)
|
|
80
|
+
end
|
|
81
|
+
register
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
class StrokeAlpha < Base
|
|
85
|
+
def self.name; "CA"; end
|
|
86
|
+
def self.invoke(processor, alpha)
|
|
87
|
+
processor.update_graphics_state(stroke_alpha: alpha.to_f)
|
|
88
|
+
end
|
|
89
|
+
register
|
|
90
|
+
end
|
|
76
91
|
end
|
|
77
92
|
end
|
|
78
93
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
module Operator
|
|
6
|
+
# Inline image operators (s8.9.7). Inline images embed raw image
|
|
7
|
+
# data directly in the content stream, framed by BI ... ID ...
|
|
8
|
+
# EI. They're an alternative to /XObject /Image for one-shot
|
|
9
|
+
# images: smaller overhead per image, no /Resources entry
|
|
10
|
+
# needed, but the bytes live in the content stream so they
|
|
11
|
+
# can't be reused.
|
|
12
|
+
#
|
|
13
|
+
# The serialise path emits the BI dict, ID marker, raw bytes,
|
|
14
|
+
# and EI marker. The invoke path is intentionally a no-op; the
|
|
15
|
+
# content Parser handles BI/ID/EI as a single bounded block
|
|
16
|
+
# rather than via the operator dispatch table.
|
|
17
|
+
class BeginInlineImage < Base
|
|
18
|
+
class << self
|
|
19
|
+
def name; "BI"; end
|
|
20
|
+
|
|
21
|
+
def serialize(serializer, **dict)
|
|
22
|
+
buf = +"BI\n"
|
|
23
|
+
dict.each do |k, v|
|
|
24
|
+
buf << serializer.serialize(k) << " " << serializer.serialize(v) << "\n"
|
|
25
|
+
end
|
|
26
|
+
buf << "ID\n"
|
|
27
|
+
buf
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def invoke(_processor, *_operands); end
|
|
31
|
+
register
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class EndInlineImage < Base
|
|
36
|
+
class << self
|
|
37
|
+
def name; "EI"; end
|
|
38
|
+
|
|
39
|
+
# The byte payload sits between ID and EI. The serializer
|
|
40
|
+
# for inline images writes the payload directly via
|
|
41
|
+
# Canvas#inline_image; this method is here so the registry
|
|
42
|
+
# knows about EI.
|
|
43
|
+
def serialize(_serializer, *_operands)
|
|
44
|
+
"EI\n"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def invoke(_processor, *_operands); end
|
|
48
|
+
register
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
# Operator implementation files. Each file defines one or more
|
|
6
|
+
# Operator::Base subclasses that register themselves on load.
|
|
7
|
+
# Eager loading is triggered by Operator.eager_load!.
|
|
8
|
+
module Operators
|
|
9
|
+
autoload :General, "pdfrb/content/operators/general"
|
|
10
|
+
autoload :Path, "pdfrb/content/operators/path"
|
|
11
|
+
autoload :Painting, "pdfrb/content/operators/painting"
|
|
12
|
+
autoload :TextState, "pdfrb/content/operators/text_state"
|
|
13
|
+
autoload :TextPositioning, "pdfrb/content/operators/text_positioning"
|
|
14
|
+
autoload :TextShowing, "pdfrb/content/operators/text_showing"
|
|
15
|
+
autoload :Color, "pdfrb/content/operators/color"
|
|
16
|
+
autoload :GraphicsStateParams, "pdfrb/content/operators/graphics_state_params"
|
|
17
|
+
autoload :MarkedContent, "pdfrb/content/operators/marked_content"
|
|
18
|
+
autoload :Clipping, "pdfrb/content/operators/clipping"
|
|
19
|
+
autoload :InlineImage, "pdfrb/content/operators/inline_image"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
module Shading
|
|
6
|
+
# Base shading builder. Subclasses set +shading_type+ and
|
|
7
|
+
# +shading_fields+. Creates a shading dict and registers it
|
|
8
|
+
# in the page's /Resources /Shading sub-dict.
|
|
9
|
+
class Base
|
|
10
|
+
attr_reader :color_space
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def shading_type
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def initialize(color_space: :DeviceGray)
|
|
19
|
+
@color_space = color_space
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Build the shading dictionary value (a Hash).
|
|
23
|
+
def to_dict
|
|
24
|
+
{ ShadingType: self.class.shading_type,
|
|
25
|
+
ColorSpace: @color_space }.merge!(shading_fields)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Register this shading on a page and return the resource name.
|
|
29
|
+
# @param document [Pdfrb::Document]
|
|
30
|
+
# @param page [Pdfrb::Model::Cos::Dictionary] target page.
|
|
31
|
+
# @return [Symbol] resource name (e.g. :Sh1)
|
|
32
|
+
def register_on(document, page)
|
|
33
|
+
shading_obj = document.add(to_dict, type: Pdfrb::Model::Cos::Dictionary)
|
|
34
|
+
ref = Pdfrb::Model::Reference.new(shading_obj.oid, shading_obj.gen)
|
|
35
|
+
resources = ensure_resources(document, page)
|
|
36
|
+
shading_dict = resources.value[:Shading]
|
|
37
|
+
if shading_dict.nil?
|
|
38
|
+
shading_dict = {}
|
|
39
|
+
resources.value[:Shading] = shading_dict
|
|
40
|
+
end
|
|
41
|
+
name = next_shading_name(shading_dict)
|
|
42
|
+
shading_dict[name] = ref
|
|
43
|
+
name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
protected
|
|
47
|
+
|
|
48
|
+
def shading_fields
|
|
49
|
+
{}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def ensure_resources(document, page)
|
|
55
|
+
resources = page.value[:Resources]
|
|
56
|
+
return resources if resources.is_a?(Pdfrb::Model::Cos::Dictionary)
|
|
57
|
+
|
|
58
|
+
resources_hash = if resources.is_a?(Pdfrb::Model::Reference)
|
|
59
|
+
document.object(resources)&.value
|
|
60
|
+
else
|
|
61
|
+
resources
|
|
62
|
+
end
|
|
63
|
+
resources_hash ||= {}
|
|
64
|
+
wrapped = Pdfrb::Model::Cos::Dictionary.new(resources_hash)
|
|
65
|
+
page.value[:Resources] = wrapped
|
|
66
|
+
wrapped
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def next_shading_name(shading_dict)
|
|
70
|
+
existing = shading_dict.keys.map(&:to_s).grep(/\ASh\d+\z/).map { |k| k[2..].to_i }
|
|
71
|
+
num = (existing.max || 0) + 1
|
|
72
|
+
:"Sh#{num}"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Axial (linear) gradient. ShadingType 2.
|
|
77
|
+
# ISO 32000-2 §8.7.4.5.4.
|
|
78
|
+
class Axial < Base
|
|
79
|
+
attr_reader :start_point, :end_point, :function, :extend
|
|
80
|
+
|
|
81
|
+
def initialize(color_space:, start_point:, end_point:,
|
|
82
|
+
function:, extend: nil)
|
|
83
|
+
super(color_space: color_space)
|
|
84
|
+
@start_point = start_point
|
|
85
|
+
@end_point = end_point
|
|
86
|
+
@function = function
|
|
87
|
+
@extend = extend
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
class << self
|
|
91
|
+
def shading_type; 2; end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
protected
|
|
95
|
+
|
|
96
|
+
def shading_fields
|
|
97
|
+
fields = {
|
|
98
|
+
Coords: Pdfrb::Model::PdfArray.new([*@start_point, *@end_point]),
|
|
99
|
+
Function: @function,
|
|
100
|
+
}
|
|
101
|
+
fields[:Extend] = Pdfrb::Model::PdfArray.new(@extend) if @extend
|
|
102
|
+
fields
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Radial gradient. ShadingType 3.
|
|
107
|
+
# ISO 32000-2 §8.7.4.5.3.
|
|
108
|
+
class Radial < Base
|
|
109
|
+
attr_reader :center1, :radius1, :center2, :radius2, :function, :extend
|
|
110
|
+
|
|
111
|
+
def initialize(color_space:, center1:, radius1:, center2:, radius2:,
|
|
112
|
+
function:, extend: nil)
|
|
113
|
+
super(color_space: color_space)
|
|
114
|
+
@center1 = center1
|
|
115
|
+
@radius1 = radius1
|
|
116
|
+
@center2 = center2
|
|
117
|
+
@radius2 = radius2
|
|
118
|
+
@function = function
|
|
119
|
+
@extend = extend
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
class << self
|
|
123
|
+
def shading_type; 3; end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
protected
|
|
127
|
+
|
|
128
|
+
def shading_fields
|
|
129
|
+
fields = {
|
|
130
|
+
Coords: Pdfrb::Model::PdfArray.new([*@center1, @radius1, *@center2, @radius2]),
|
|
131
|
+
Function: @function,
|
|
132
|
+
}
|
|
133
|
+
fields[:Extend] = Pdfrb::Model::PdfArray.new(@extend) if @extend
|
|
134
|
+
fields
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Content
|
|
5
|
+
# Shading patterns (ISO 32000-2 §8.7.4). Shadings define smooth
|
|
6
|
+
# color transitions: axial (linear) gradients, radial gradients,
|
|
7
|
+
# and free-form Gouraud-triangle meshes.
|
|
8
|
+
#
|
|
9
|
+
# Each shading is a dictionary with /ShadingType and type-specific
|
|
10
|
+
# parameters. Registered in page Resources under /Shading.
|
|
11
|
+
module Shading
|
|
12
|
+
autoload :Base, "pdfrb/content/shading/base"
|
|
13
|
+
autoload :Axial, "pdfrb/content/shading/base"
|
|
14
|
+
autoload :Radial, "pdfrb/content/shading/base"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|