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
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# Refinements on Numeric to convert CSS-style units to PDF points.
|
|
6
|
+
#
|
|
7
|
+
# Usage:
|
|
8
|
+
# using Pdfrb::Layout::NumericRefinements
|
|
9
|
+
# 2.cm # => 56.6929...
|
|
10
|
+
# 1.inch # => 72.0
|
|
11
|
+
module NumericRefinements
|
|
12
|
+
PT_PER_INCH = 72.0
|
|
13
|
+
PT_PER_CM = PT_PER_INCH / 2.54
|
|
14
|
+
PT_PER_MM = PT_PER_CM / 10.0
|
|
15
|
+
|
|
16
|
+
refine Numeric do
|
|
17
|
+
def pt
|
|
18
|
+
to_f
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def cm
|
|
22
|
+
to_f * PT_PER_CM
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def mm
|
|
26
|
+
to_f * PT_PER_MM
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def inch
|
|
30
|
+
to_f * PT_PER_INCH
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
alias inches inch
|
|
34
|
+
|
|
35
|
+
def pixel(dpi: 96.0)
|
|
36
|
+
to_f * (PT_PER_INCH / dpi)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
alias px pixel
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# A named page template. A PageStyle knows:
|
|
6
|
+
# - page dimensions (size + orientation)
|
|
7
|
+
# - margin
|
|
8
|
+
# - the next page style (chains)
|
|
9
|
+
# - a block that draws page chrome (header/footer) each time a
|
|
10
|
+
# new page with this style is created.
|
|
11
|
+
class PageStyle
|
|
12
|
+
attr_reader :name, :page_size, :orientation, :margin, :next_style, :block
|
|
13
|
+
|
|
14
|
+
PAGE_SIZES = {
|
|
15
|
+
A4: [595.28, 841.89],
|
|
16
|
+
A3: [841.89, 1190.55],
|
|
17
|
+
A5: [419.53, 595.28],
|
|
18
|
+
Letter: [612.0, 792.0],
|
|
19
|
+
Legal: [612.0, 1008.0],
|
|
20
|
+
Tabloid: [792.0, 1224.0],
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
def initialize(name:, page_size: :A4, orientation: :portrait,
|
|
24
|
+
margin: 36, next_style: nil, &block)
|
|
25
|
+
@name = name
|
|
26
|
+
@page_size = page_size
|
|
27
|
+
@orientation = orientation
|
|
28
|
+
@margin = margin
|
|
29
|
+
@next_style = next_style || name
|
|
30
|
+
@block = block
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def dimensions
|
|
34
|
+
base = PAGE_SIZES[@page_size] || [612.0, 792.0]
|
|
35
|
+
if @orientation == :landscape
|
|
36
|
+
[base[1], base[0]]
|
|
37
|
+
else
|
|
38
|
+
base
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def width
|
|
43
|
+
dimensions[0]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def height
|
|
47
|
+
dimensions[1]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def frame
|
|
51
|
+
m = @margin.is_a?(Array) ? @margin : [@margin] * 4
|
|
52
|
+
Frame.new(
|
|
53
|
+
left: m[3],
|
|
54
|
+
bottom: m[2],
|
|
55
|
+
width: width - m[1] - m[3],
|
|
56
|
+
height: height - m[0] - m[2]
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def draw_chrome(canvas)
|
|
61
|
+
@block&.call(canvas)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# Immutable typographic + visual style. Updating a property
|
|
6
|
+
# returns a new Style; the original is unchanged.
|
|
7
|
+
#
|
|
8
|
+
# Built-in presets (:base, :title, :heading1, :heading2, :heading3,
|
|
9
|
+
# :code, :caption) can be loaded via +Style.new(:heading1)+ or
|
|
10
|
+
# merged via +Style.new(base: :heading1, **overrides)+.
|
|
11
|
+
class Style
|
|
12
|
+
PROPERTIES = %i[
|
|
13
|
+
font_name font_size font_options fill_color stroke_color
|
|
14
|
+
fill_alpha stroke_alpha line_width line_spacing character_spacing
|
|
15
|
+
word_spacing text_align vertical_align text_rendering_mode
|
|
16
|
+
text_rise font_features text_decoration text_underline_color
|
|
17
|
+
subscript superscript border padding margin border_color
|
|
18
|
+
border_style border_radius background background_alpha
|
|
19
|
+
overlap_overflow_alpha position text_transform word_break
|
|
20
|
+
hyphenate language first_line_indent text_indent
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
PRESETS = {
|
|
24
|
+
base: { font_name: "Helvetica", font_size: 10, line_spacing: 1.2,
|
|
25
|
+
fill_color: [0, 0, 0] },
|
|
26
|
+
title: { font_name: "Helvetica-Bold", font_size: 24,
|
|
27
|
+
fill_color: [0, 0, 0] },
|
|
28
|
+
heading1: { font_name: "Helvetica-Bold", font_size: 20,
|
|
29
|
+
fill_color: [0, 0, 0] },
|
|
30
|
+
heading2: { font_name: "Helvetica-Bold", font_size: 16 },
|
|
31
|
+
heading3: { font_name: "Helvetica-BoldOblique", font_size: 14 },
|
|
32
|
+
code: { font_name: "Courier", font_size: 10 },
|
|
33
|
+
caption: { font_name: "Helvetica-Oblique", font_size: 9,
|
|
34
|
+
fill_color: [0.3, 0.3, 0.3] },
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
def initialize(name_or_base = nil, **opts)
|
|
38
|
+
base = if name_or_base.is_a?(Hash)
|
|
39
|
+
name_or_base
|
|
40
|
+
elsif name_or_base.is_a?(Symbol)
|
|
41
|
+
PRESETS[name_or_base] || {}
|
|
42
|
+
else
|
|
43
|
+
{}
|
|
44
|
+
end
|
|
45
|
+
@values = base.merge(opts).freeze
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def update(**opts)
|
|
49
|
+
self.class.new(@values.merge(opts))
|
|
50
|
+
end
|
|
51
|
+
alias dup_with update
|
|
52
|
+
|
|
53
|
+
def to_h
|
|
54
|
+
@values.dup
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
PROPERTIES.each do |prop|
|
|
58
|
+
define_method(prop) { @values[prop] }
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# A table of cells. Each cell holds a Box. Column widths are auto
|
|
6
|
+
# unless specified; row heights computed from content.
|
|
7
|
+
class TableBox < Box
|
|
8
|
+
attr_reader :rows, :column_widths
|
|
9
|
+
|
|
10
|
+
def initialize(rows:, column_widths: nil, **)
|
|
11
|
+
super(**)
|
|
12
|
+
@rows = rows
|
|
13
|
+
@column_widths = column_widths
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fit?(available_width, available_height)
|
|
17
|
+
compute_column_widths(available_width)
|
|
18
|
+
remaining = available_height
|
|
19
|
+
@rows.each do |row|
|
|
20
|
+
row_heights = []
|
|
21
|
+
row.each_with_index do |cell, col|
|
|
22
|
+
cell_w = @column_widths[col]
|
|
23
|
+
cell.fit?(cell_w, remaining) or return false
|
|
24
|
+
row_heights << cell.height
|
|
25
|
+
end
|
|
26
|
+
row_h = row_heights.max || 0
|
|
27
|
+
remaining -= row_h
|
|
28
|
+
end
|
|
29
|
+
@width = available_width
|
|
30
|
+
@height = available_height - remaining
|
|
31
|
+
true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def draw_content(canvas, x, y)
|
|
35
|
+
offset_y = y
|
|
36
|
+
@rows.each do |row|
|
|
37
|
+
max_h = 0
|
|
38
|
+
offset_x = x
|
|
39
|
+
row.each_with_index do |cell, col|
|
|
40
|
+
cell.draw(canvas, offset_x, offset_y)
|
|
41
|
+
offset_x += @column_widths[col]
|
|
42
|
+
max_h = cell.height if cell.height > max_h
|
|
43
|
+
end
|
|
44
|
+
offset_y -= max_h
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def empty?
|
|
49
|
+
@rows.empty?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def compute_column_widths(available_width)
|
|
55
|
+
return @column_widths = equal_widths(available_width) if @column_widths.nil?
|
|
56
|
+
|
|
57
|
+
@column_widths.map!(&:to_f)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def equal_widths(available_width)
|
|
61
|
+
col_count = @rows.first&.size || 1
|
|
62
|
+
Array.new(col_count, available_width / col_count)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# Renders a string of text with word-wrap into a region. Uses
|
|
6
|
+
# TextLayouter internally.
|
|
7
|
+
class TextBox < Box
|
|
8
|
+
attr_reader :text, :lines
|
|
9
|
+
|
|
10
|
+
def initialize(text:, **)
|
|
11
|
+
super(**)
|
|
12
|
+
@text = text.to_s
|
|
13
|
+
@lines = []
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def fit?(available_width, available_height)
|
|
17
|
+
layouter = TextLayouter.new(@style)
|
|
18
|
+
@lines = layouter.layout(@text, available_width)
|
|
19
|
+
@width = available_width
|
|
20
|
+
@height = @lines.sum(&:height)
|
|
21
|
+
@height <= available_height
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def draw_content(canvas, x, y)
|
|
25
|
+
offset_y = y - (@lines.first&.ascender || 0)
|
|
26
|
+
@lines.each do |line|
|
|
27
|
+
line.draw(canvas, x, offset_y, available_width: @width,
|
|
28
|
+
alignment: @style.text_align || :left)
|
|
29
|
+
offset_y -= line.height
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def empty?
|
|
34
|
+
@text.empty?
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# A single fragment of styled text — one run of consecutive glyphs
|
|
6
|
+
# with the same Style. Pieces are [[glyph_id, x_offset, width], ...]
|
|
7
|
+
# in font units.
|
|
8
|
+
class TextFragment
|
|
9
|
+
attr_reader :pieces, :style, :width, :height, :y_min, :y_max
|
|
10
|
+
|
|
11
|
+
def initialize(pieces:, style:, width:, height:, y_min:, y_max:)
|
|
12
|
+
@pieces = pieces
|
|
13
|
+
@style = style
|
|
14
|
+
@width = width
|
|
15
|
+
@height = height
|
|
16
|
+
@y_min = y_min
|
|
17
|
+
@y_max = y_max
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def ascender
|
|
21
|
+
@y_max
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def descender
|
|
25
|
+
-@y_min
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def draw(canvas, x, y)
|
|
29
|
+
canvas.save_graphics_state do
|
|
30
|
+
if @style.fill_color
|
|
31
|
+
canvas.fill_color(@style.fill_color)
|
|
32
|
+
end
|
|
33
|
+
canvas.text(@pieces.map(&:first).pack("U*"), at: [x, y],
|
|
34
|
+
font: font_name_for_canvas, size: @style.font_size)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def font_name_for_canvas
|
|
41
|
+
@style.font_name || :Helvetica
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Layout
|
|
5
|
+
# Breaks a string into Layout::Line instances that fit a given
|
|
6
|
+
# width. Uses real per-glyph widths from the font's AFM or hmtx
|
|
7
|
+
# table when available, falling back to a heuristic estimate.
|
|
8
|
+
class TextLayouter
|
|
9
|
+
attr_reader :style
|
|
10
|
+
|
|
11
|
+
def initialize(style)
|
|
12
|
+
@style = style
|
|
13
|
+
@metrics = lookup_metrics
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @param text [String] the text to lay out.
|
|
17
|
+
# @param width [Float] target line width in PDF units.
|
|
18
|
+
# @return [Array<Line>] lines, each fitting in +width+.
|
|
19
|
+
def layout(text, width)
|
|
20
|
+
reordered = reorder_for_layout(text.to_s)
|
|
21
|
+
clusters = reordered.grapheme_clusters
|
|
22
|
+
return [] if clusters.empty?
|
|
23
|
+
|
|
24
|
+
lines = []
|
|
25
|
+
current = []
|
|
26
|
+
current_width = 0.0
|
|
27
|
+
clusters.each do |cluster|
|
|
28
|
+
cw = cluster_width(cluster)
|
|
29
|
+
if current_width + cw > width && !current.empty?
|
|
30
|
+
lines << build_line(current)
|
|
31
|
+
current = []
|
|
32
|
+
current_width = 0.0
|
|
33
|
+
end
|
|
34
|
+
current << cluster
|
|
35
|
+
current_width += cw
|
|
36
|
+
end
|
|
37
|
+
lines << build_line(current) unless current.empty?
|
|
38
|
+
lines
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def reorder_for_layout(text)
|
|
44
|
+
return text unless Pdfrb::Layout::Bidi.rtl?(text)
|
|
45
|
+
|
|
46
|
+
Pdfrb::Layout::Bidi.reorder(text)
|
|
47
|
+
rescue StandardError
|
|
48
|
+
text
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def lookup_metrics
|
|
52
|
+
font_name = @style.font_name
|
|
53
|
+
Pdfrb::Font::MetricsHelper.metrics_for_standard14(font_name)
|
|
54
|
+
rescue StandardError
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def cluster_width(cluster)
|
|
59
|
+
size = @style.font_size || 10
|
|
60
|
+
upem = @metrics&.units_per_em || 1000
|
|
61
|
+
|
|
62
|
+
if @metrics
|
|
63
|
+
total = 0.0
|
|
64
|
+
cluster.each_codepoint do |cp|
|
|
65
|
+
width_in_font_units = glyph_width_in_font_units(cp)
|
|
66
|
+
total += width_in_font_units
|
|
67
|
+
end
|
|
68
|
+
total * size / upem
|
|
69
|
+
else
|
|
70
|
+
# Heuristic fallback when no AFM available.
|
|
71
|
+
size * cluster.length * 0.5
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def glyph_width_in_font_units(codepoint)
|
|
76
|
+
# Map Unicode codepoint → glyph name → AFM width.
|
|
77
|
+
glyph_name = unicode_to_glyph_name(codepoint)
|
|
78
|
+
return 500 unless glyph_name && @metrics
|
|
79
|
+
|
|
80
|
+
afm = afm_for(@style.font_name)
|
|
81
|
+
return 500 unless afm
|
|
82
|
+
|
|
83
|
+
width = afm.width_for(glyph_name)
|
|
84
|
+
width.positive? ? width : 500
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def unicode_to_glyph_name(codepoint)
|
|
88
|
+
table = begin
|
|
89
|
+
Pdfrb::Font::Encoding::WinAnsiEncoding::TABLE
|
|
90
|
+
rescue StandardError
|
|
91
|
+
nil
|
|
92
|
+
end
|
|
93
|
+
return nil unless table
|
|
94
|
+
|
|
95
|
+
table[codepoint]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def afm_for(font_name)
|
|
99
|
+
@afm_cache ||= {}
|
|
100
|
+
return @afm_cache[font_name] if @afm_cache.key?(font_name)
|
|
101
|
+
|
|
102
|
+
@afm_cache[font_name] = Pdfrb::Font::MetricsHelper.afm_for(font_name.to_s)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def build_line(clusters)
|
|
106
|
+
pieces = clusters.map.with_index { |c, i| [c.ord, i, cluster_width(c)] }
|
|
107
|
+
size = @style.font_size || 10
|
|
108
|
+
ascender = @metrics ? @metrics.ascender(size) : size
|
|
109
|
+
descender = @metrics ? @metrics.descender(size) : -size * 0.2
|
|
110
|
+
Line.new(fragments: [
|
|
111
|
+
TextFragment.new(
|
|
112
|
+
pieces: pieces,
|
|
113
|
+
style: @style,
|
|
114
|
+
width: pieces.sum { |p| p[2] },
|
|
115
|
+
height: ascender - descender,
|
|
116
|
+
y_min: descender,
|
|
117
|
+
y_max: ascender
|
|
118
|
+
),
|
|
119
|
+
])
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
data/lib/pdfrb/layout.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
# Layout engine (mirrors HexaPDF::Layout). High-level document
|
|
5
|
+
# composition: Frame + Box + Composer. Boxes (text, image, table,
|
|
6
|
+
# list) are placed into Frames which represent page regions. Content
|
|
7
|
+
# flows across pages when a Frame fills up.
|
|
8
|
+
module Layout
|
|
9
|
+
autoload :Frame, "pdfrb/layout/frame"
|
|
10
|
+
autoload :Style, "pdfrb/layout/style"
|
|
11
|
+
autoload :NumericRefinements, "pdfrb/layout/numeric_refinements"
|
|
12
|
+
autoload :Box, "pdfrb/layout/box"
|
|
13
|
+
autoload :ContainerBox, "pdfrb/layout/container_box"
|
|
14
|
+
autoload :TextBox, "pdfrb/layout/text_box"
|
|
15
|
+
autoload :ImageBox, "pdfrb/layout/image_box"
|
|
16
|
+
autoload :ListBox, "pdfrb/layout/list_box"
|
|
17
|
+
autoload :TableBox, "pdfrb/layout/table_box"
|
|
18
|
+
autoload :ColumnBox, "pdfrb/layout/column_box"
|
|
19
|
+
autoload :InlineBox, "pdfrb/layout/inline_box"
|
|
20
|
+
autoload :BoxFitter, "pdfrb/layout/box_fitter"
|
|
21
|
+
autoload :PageStyle, "pdfrb/layout/page_style"
|
|
22
|
+
autoload :TextLayouter, "pdfrb/layout/text_layouter"
|
|
23
|
+
autoload :TextFragment, "pdfrb/layout/text_fragment"
|
|
24
|
+
autoload :Line, "pdfrb/layout/line"
|
|
25
|
+
autoload :Bidi, "pdfrb/layout/bidi"
|
|
26
|
+
autoload :RomanNumeral, "pdfrb/layout/list_box"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
require "zlib"
|
|
5
|
+
|
|
6
|
+
module Pdfrb
|
|
7
|
+
module Linearization
|
|
8
|
+
# Builds the page-offset hint stream (ISO 32000-2 Annex F).
|
|
9
|
+
# The hint stream tells the viewer where each page's objects are
|
|
10
|
+
# located without needing to parse the full xref.
|
|
11
|
+
#
|
|
12
|
+
# This implementation produces a minimal valid hint table:
|
|
13
|
+
# /S 16 (16 bits per entry field)
|
|
14
|
+
# One page-offset entry per page.
|
|
15
|
+
class HintStream
|
|
16
|
+
DEFAULT_ITEM_BITS = 16
|
|
17
|
+
|
|
18
|
+
attr_reader :page_entries, :item_bits
|
|
19
|
+
|
|
20
|
+
def initialize(item_bits: DEFAULT_ITEM_BITS)
|
|
21
|
+
@item_bits = item_bits
|
|
22
|
+
@page_entries = []
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Add a page entry.
|
|
26
|
+
# @param offset_delta [Integer] offset relative to /O reference.
|
|
27
|
+
# @param page_length [Integer] length in bytes.
|
|
28
|
+
# @param num_objects [Integer] number of objects on this page.
|
|
29
|
+
# @param page_obj_num [Integer] object number of the Page dict.
|
|
30
|
+
def add_page(offset_delta:, page_length:, num_objects:, page_obj_num:)
|
|
31
|
+
@page_entries << {
|
|
32
|
+
offset_delta: offset_delta,
|
|
33
|
+
page_length: page_length,
|
|
34
|
+
num_objects: num_objects,
|
|
35
|
+
page_obj_num: page_obj_num,
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Encode the hint stream as PDF bytes (binary, ready for /Length).
|
|
40
|
+
# @return [String] binary hint table data.
|
|
41
|
+
def encode
|
|
42
|
+
bits = []
|
|
43
|
+
|
|
44
|
+
@page_entries.each do |entry|
|
|
45
|
+
bits << [entry[:offset_delta], @item_bits]
|
|
46
|
+
bits << [entry[:page_length], @item_bits]
|
|
47
|
+
bits << [entry[:num_objects], @item_bits]
|
|
48
|
+
bits << [entry[:page_obj_num], @item_bits]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
packed = pack_bits(bits)
|
|
52
|
+
packed.force_encoding(Encoding::BINARY)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Dictionary fields for the hint stream object.
|
|
56
|
+
def dictionary_fields(length)
|
|
57
|
+
{
|
|
58
|
+
S: @item_bits,
|
|
59
|
+
}.tap do |h|
|
|
60
|
+
h[:Length] = length
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def pack_bits(bit_fields)
|
|
67
|
+
bytes = +""
|
|
68
|
+
buffer = 0
|
|
69
|
+
bits_in_buffer = 0
|
|
70
|
+
|
|
71
|
+
bit_fields.each do |value, width|
|
|
72
|
+
width.times do |i|
|
|
73
|
+
bit = (value >> (width - 1 - i)) & 1
|
|
74
|
+
buffer = (buffer << 1) | bit
|
|
75
|
+
bits_in_buffer += 1
|
|
76
|
+
if bits_in_buffer == 8
|
|
77
|
+
bytes << [buffer].pack("C")
|
|
78
|
+
buffer = 0
|
|
79
|
+
bits_in_buffer = 0
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
if bits_in_buffer.positive?
|
|
85
|
+
buffer <<= (8 - bits_in_buffer)
|
|
86
|
+
bytes << [buffer].pack("C")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
bytes
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|