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
|
@@ -7,10 +7,13 @@ module Pdfrb
|
|
|
7
7
|
class AFMParser
|
|
8
8
|
attr_reader :font_name, :full_name, :family_name,
|
|
9
9
|
:encoding_scheme, :bbox, :cap_height, :x_height,
|
|
10
|
-
:ascender, :descender, :
|
|
10
|
+
:ascender, :descender, :italic_angle,
|
|
11
|
+
:average_width, :max_width, :char_metrics
|
|
11
12
|
|
|
12
13
|
def initialize
|
|
13
14
|
@char_metrics = {}
|
|
15
|
+
@average_width = nil
|
|
16
|
+
@max_width = nil
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
def self.parse(text)
|
|
@@ -25,35 +28,48 @@ module Pdfrb
|
|
|
25
28
|
in_char_metrics = false
|
|
26
29
|
text.each_line do |line|
|
|
27
30
|
line = line.strip
|
|
28
|
-
|
|
29
|
-
@font_name = line.split(" ", 2)[1]
|
|
30
|
-
elsif line.start_with?("FullName ")
|
|
31
|
-
@full_name = line.split(" ", 2)[1]
|
|
32
|
-
elsif line.start_with?("FamilyName ")
|
|
33
|
-
@family_name = line.split(" ", 2)[1]
|
|
34
|
-
elsif line.start_with?("EncodingScheme ")
|
|
35
|
-
@encoding_scheme = line.split(" ", 2)[1]
|
|
36
|
-
elsif line.start_with?("FontBBox ")
|
|
37
|
-
@bbox = line.split.drop(1).map(&:to_f)
|
|
38
|
-
elsif line.start_with?("CapHeight ")
|
|
39
|
-
@cap_height = line.split[1].to_f
|
|
40
|
-
elsif line.start_with?("XHeight ")
|
|
41
|
-
@x_height = line.split[1].to_f
|
|
42
|
-
elsif line.start_with?("Ascender ")
|
|
43
|
-
@ascender = line.split[1].to_f
|
|
44
|
-
elsif line.start_with?("Descender ")
|
|
45
|
-
@descender = line.split[1].to_f
|
|
46
|
-
elsif line == "StartCharMetrics" || line.start_with?("StartCharMetrics ")
|
|
47
|
-
in_char_metrics = true
|
|
48
|
-
elsif line == "EndCharMetrics" || line.start_with?("EndCharMetrics")
|
|
49
|
-
in_char_metrics = false
|
|
50
|
-
elsif in_char_metrics && line.start_with?("C ")
|
|
51
|
-
parse_char_metric(line)
|
|
52
|
-
end
|
|
31
|
+
in_char_metrics = parse_line(line, in_char_metrics)
|
|
53
32
|
end
|
|
54
33
|
self
|
|
55
34
|
end
|
|
56
35
|
|
|
36
|
+
def parse_line(line, in_char_metrics)
|
|
37
|
+
return handle_state_change(line, in_char_metrics) if parse_global_metric(line) == :handled
|
|
38
|
+
|
|
39
|
+
handle_state_change(line, in_char_metrics)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def handle_state_change(line, in_char_metrics)
|
|
43
|
+
if line.start_with?("StartCharMetrics")
|
|
44
|
+
true
|
|
45
|
+
elsif line.start_with?("EndCharMetrics")
|
|
46
|
+
compute_average_and_max_widths
|
|
47
|
+
false
|
|
48
|
+
elsif in_char_metrics && line.start_with?("C ")
|
|
49
|
+
parse_char_metric(line)
|
|
50
|
+
in_char_metrics
|
|
51
|
+
else
|
|
52
|
+
in_char_metrics
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def parse_global_metric(line)
|
|
57
|
+
case line
|
|
58
|
+
when /\AFontName / then @font_name = line.split(" ", 2)[1]
|
|
59
|
+
when /\AFullName / then @full_name = line.split(" ", 2)[1]
|
|
60
|
+
when /\AFamilyName / then @family_name = line.split(" ", 2)[1]
|
|
61
|
+
when /\AEncodingScheme / then @encoding_scheme = line.split(" ", 2)[1]
|
|
62
|
+
when /\AFontBBox / then @bbox = line.split.drop(1).map(&:to_f)
|
|
63
|
+
when /\ACapHeight / then @cap_height = line.split[1].to_f
|
|
64
|
+
when /\AXHeight / then @x_height = line.split[1].to_f
|
|
65
|
+
when /\AAscender / then @ascender = line.split[1].to_f
|
|
66
|
+
when /\ADescender / then @descender = line.split[1].to_f
|
|
67
|
+
when /\AItalicAngle / then @italic_angle = line.split[1].to_f
|
|
68
|
+
else return nil
|
|
69
|
+
end
|
|
70
|
+
:handled
|
|
71
|
+
end
|
|
72
|
+
|
|
57
73
|
def width_for(glyph_name_or_code)
|
|
58
74
|
metric = @char_metrics[glyph_name_or_code] ||
|
|
59
75
|
@char_metrics[glyph_name_or_code.to_i]
|
|
@@ -62,6 +78,14 @@ module Pdfrb
|
|
|
62
78
|
|
|
63
79
|
private
|
|
64
80
|
|
|
81
|
+
def compute_average_and_max_widths
|
|
82
|
+
widths = @char_metrics.values.filter_map { |m| m[:width] }
|
|
83
|
+
return if widths.empty?
|
|
84
|
+
|
|
85
|
+
@average_width = widths.sum / widths.length
|
|
86
|
+
@max_width = widths.max
|
|
87
|
+
end
|
|
88
|
+
|
|
65
89
|
def parse_char_metric(line)
|
|
66
90
|
parts = line.split(";").map(&:strip)
|
|
67
91
|
code = nil
|
|
@@ -12,6 +12,15 @@ module Pdfrb
|
|
|
12
12
|
# chunking of bfchar sections (max 100 entries per section per
|
|
13
13
|
# the PDF spec).
|
|
14
14
|
class Writer
|
|
15
|
+
def self.write(mapping, name: "Adobe-Identity-UCS")
|
|
16
|
+
str_mapping = mapping.transform_values { |cp| [cp].pack("U") }
|
|
17
|
+
new(
|
|
18
|
+
cmap_name: name,
|
|
19
|
+
cid_system_info: { registry: "Adobe", ordering: "UCS", supplement: 0 },
|
|
20
|
+
mapping: str_mapping,
|
|
21
|
+
code_size: 1,
|
|
22
|
+
).to_s
|
|
23
|
+
end
|
|
15
24
|
MAX_BFCHAR_ENTRIES = 100
|
|
16
25
|
|
|
17
26
|
attr_reader :cmap_name, :cid_system_info, :mapping
|
|
@@ -19,6 +19,23 @@ module Pdfrb
|
|
|
19
19
|
}.each { |b, cp| TABLE[b] = cp }
|
|
20
20
|
(0xA0..0xFF).each { |b| TABLE[b] = b }
|
|
21
21
|
TABLE.freeze
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
def encode(text)
|
|
25
|
+
Pdfrb::Font::Encoding.encode(:WinAnsiEncoding, text)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def decode(bytes)
|
|
29
|
+
Pdfrb::Font::Encoding.decode(:WinAnsiEncoding, bytes)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def encodable?(codepoint)
|
|
33
|
+
return true if codepoint < 0x80
|
|
34
|
+
|
|
35
|
+
reverse = Pdfrb::Font::Encoding.reverse_table_for(:WinAnsiEncoding)
|
|
36
|
+
!reverse[codepoint].nil?
|
|
37
|
+
end
|
|
38
|
+
end
|
|
22
39
|
end
|
|
23
40
|
end
|
|
24
41
|
end
|
data/lib/pdfrb/font/encoding.rb
CHANGED
|
@@ -10,17 +10,28 @@ module Pdfrb
|
|
|
10
10
|
autoload :ZapfDingbatsEncoding, "pdfrb/font/encoding/zapf_dingbats_encoding"
|
|
11
11
|
|
|
12
12
|
class << self
|
|
13
|
-
# Decode +bytes+ (one byte per glyph) using +encoding_name+
|
|
14
|
-
# (a Symbol like :WinAnsiEncoding) to Unicode.
|
|
15
13
|
def decode(encoding_name, bytes)
|
|
16
14
|
table = table_for(encoding_name)
|
|
17
15
|
return bytes unless table
|
|
18
16
|
|
|
19
17
|
bytes.each_byte.with_object(+"") do |b, buf|
|
|
20
|
-
|
|
18
|
+
cp = table.is_a?(::Array) ? table[b] : table[b.to_s.to_sym]
|
|
19
|
+
buf << (cp ? [cp].pack("U") : "?")
|
|
21
20
|
end.encode("UTF-8")
|
|
22
21
|
end
|
|
23
22
|
|
|
23
|
+
def encode(encoding_name, text)
|
|
24
|
+
table = table_for(encoding_name)
|
|
25
|
+
return text.to_s.b unless table
|
|
26
|
+
|
|
27
|
+
reverse = reverse_table_for(encoding_name)
|
|
28
|
+
text.to_s.each_char.with_object(+"") do |ch, buf|
|
|
29
|
+
cp = ch.ord
|
|
30
|
+
byte = reverse[cp] || (cp < 0x80 ? cp : nil)
|
|
31
|
+
buf << [byte || 0x3F].pack("C")
|
|
32
|
+
end.b
|
|
33
|
+
end
|
|
34
|
+
|
|
24
35
|
def table_for(name)
|
|
25
36
|
case name.to_sym
|
|
26
37
|
when :WinAnsiEncoding then WinAnsiEncoding::TABLE
|
|
@@ -30,6 +41,24 @@ module Pdfrb
|
|
|
30
41
|
when :ZapfDingbatsEncoding then ZapfDingbatsEncoding::TABLE
|
|
31
42
|
end
|
|
32
43
|
end
|
|
44
|
+
|
|
45
|
+
def reverse_table_for(name)
|
|
46
|
+
@reverse_tables ||= {}
|
|
47
|
+
@reverse_tables[name] ||= build_reverse_table(name)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def build_reverse_table(name)
|
|
51
|
+
table = table_for(name)
|
|
52
|
+
return {} unless table
|
|
53
|
+
|
|
54
|
+
if table.is_a?(::Array)
|
|
55
|
+
table.each_with_index.with_object({}) do |(cp, byte), h|
|
|
56
|
+
h[cp] = byte if cp
|
|
57
|
+
end
|
|
58
|
+
else
|
|
59
|
+
table.each_with_object({}) { |(byte, cp), h| h[cp] = byte }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
33
62
|
end
|
|
34
63
|
end
|
|
35
64
|
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
# Metrics value object + lookup helper. Returns ascent/descent/
|
|
6
|
+
# cap_height/x_height/line_gap/avg_width for any font (Standard 14
|
|
7
|
+
# via AFM, embedded TTF/OTF via head/hhea/OS2 tables).
|
|
8
|
+
Metrics = Struct.new(:font_name, :units_per_em, :ascent, :descent,
|
|
9
|
+
:cap_height, :x_height, :line_gap, :avg_width,
|
|
10
|
+
:max_width, :stem_v, :italic_angle, :bbox,
|
|
11
|
+
keyword_init: true) do
|
|
12
|
+
def line_height(font_size)
|
|
13
|
+
((ascent || 800) - (descent || -200) + (line_gap || 0)) *
|
|
14
|
+
font_size.to_f / (units_per_em || 1000)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ascender(font_size)
|
|
18
|
+
(ascent || 800) * font_size.to_f / (units_per_em || 1000)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def descender(font_size)
|
|
22
|
+
(descent || -200) * font_size.to_f / (units_per_em || 1000)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module MetricsHelper
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
# Look up metrics for a Standard 14 font name.
|
|
30
|
+
# @param font_name [String, Symbol] e.g., "Helvetica", "Times-Roman".
|
|
31
|
+
# @return [Pdfrb::Font::Metrics, nil]
|
|
32
|
+
def metrics_for_standard14(font_name)
|
|
33
|
+
afm = afm_for(font_name.to_s)
|
|
34
|
+
return nil unless afm
|
|
35
|
+
|
|
36
|
+
Metrics.new(
|
|
37
|
+
font_name: font_name.to_s,
|
|
38
|
+
units_per_em: 1000,
|
|
39
|
+
ascent: afm.ascender,
|
|
40
|
+
descent: afm.descender,
|
|
41
|
+
cap_height: afm.cap_height,
|
|
42
|
+
x_height: afm.x_height,
|
|
43
|
+
line_gap: 0,
|
|
44
|
+
avg_width: afm.average_width,
|
|
45
|
+
max_width: afm.max_width,
|
|
46
|
+
stem_v: 80,
|
|
47
|
+
italic_angle: afm.italic_angle || 0,
|
|
48
|
+
bbox: afm.bbox
|
|
49
|
+
)
|
|
50
|
+
rescue StandardError
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Look up metrics from raw TTF/OTF bytes.
|
|
55
|
+
# @param font_data [String] raw TTF or OTF bytes.
|
|
56
|
+
# @return [Pdfrb::Font::Metrics, nil]
|
|
57
|
+
def metrics_for_ttf(font_data)
|
|
58
|
+
return nil unless font_data && font_data.bytesize >= 4
|
|
59
|
+
|
|
60
|
+
ttf = Pdfrb::Font::TrueType::File.new(font_data)
|
|
61
|
+
head = ttf.head_table_parsed
|
|
62
|
+
hhea = ttf.hhea_table_parsed
|
|
63
|
+
os2 = ttf.os2_table_parsed
|
|
64
|
+
return nil unless head && hhea
|
|
65
|
+
|
|
66
|
+
Metrics.new(
|
|
67
|
+
font_name: ttf.name_table_parsed&.ps_name || "EmbeddedFont",
|
|
68
|
+
units_per_em: head.units_per_em || 1000,
|
|
69
|
+
ascent: hhea.ascender || os2&.s_typo_ascender || 800,
|
|
70
|
+
descent: hhea.descender || os2&.s_typo_descender || -200,
|
|
71
|
+
cap_height: os2&.s_cap_height || 700,
|
|
72
|
+
x_height: 500,
|
|
73
|
+
line_gap: hhea.line_gap || 0,
|
|
74
|
+
avg_width: 500,
|
|
75
|
+
max_width: hhea.advance_width_max || 1000,
|
|
76
|
+
stem_v: 80,
|
|
77
|
+
italic_angle: (head.italic? ? -12 : 0),
|
|
78
|
+
bbox: head.bbox
|
|
79
|
+
)
|
|
80
|
+
rescue StandardError
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Convenience: dispatch on font_name vs raw bytes.
|
|
85
|
+
def metrics_for(font_name_or_data)
|
|
86
|
+
case font_name_or_data
|
|
87
|
+
when String
|
|
88
|
+
if font_name_or_data.bytesize >= 4 && valid_magic?(font_name_or_data)
|
|
89
|
+
metrics_for_ttf(font_name_or_data)
|
|
90
|
+
else
|
|
91
|
+
metrics_for_standard14(font_name_or_data)
|
|
92
|
+
end
|
|
93
|
+
when Symbol then metrics_for_standard14(font_name_or_data)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def valid_magic?(bytes)
|
|
98
|
+
magic = bytes.byteslice(0, 4)
|
|
99
|
+
["\x00\x01\x00\x00".b, "OTTO".b, "true".b, "ttcf".b].include?(magic)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def afm_for(name)
|
|
103
|
+
@afm_cache ||= {}
|
|
104
|
+
return @afm_cache[name] if @afm_cache.key?(name)
|
|
105
|
+
|
|
106
|
+
path = standard14_afm_path(name)
|
|
107
|
+
return @afm_cache[name] = nil unless path && File.exist?(path)
|
|
108
|
+
|
|
109
|
+
@afm_cache[name] = Pdfrb::Font::AFMParser.parse(File.read(path))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def standard14_afm_path(name)
|
|
113
|
+
# __dir__ is lib/pdfrb/font/. Three .. gets to project root
|
|
114
|
+
# (lib/pdfrb/font → lib/pdfrb → lib → project root). Data
|
|
115
|
+
# files live at <root>/data/pdfrb/afm/.
|
|
116
|
+
base = File.expand_path("../../../data/pdfrb/afm", __dir__)
|
|
117
|
+
File.join(base, "#{name}.afm")
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -7,10 +7,11 @@ module Pdfrb
|
|
|
7
7
|
# sfnt header + table directory; lazy-loads individual tables
|
|
8
8
|
# on access.
|
|
9
9
|
class File
|
|
10
|
-
attr_reader :tables, :num_tables
|
|
10
|
+
attr_reader :tables, :num_tables, :raw_data
|
|
11
11
|
|
|
12
12
|
def initialize(data)
|
|
13
13
|
@data = data.b
|
|
14
|
+
@raw_data = @data
|
|
14
15
|
@tables = {}
|
|
15
16
|
parse_directory
|
|
16
17
|
end
|
|
@@ -40,9 +41,17 @@ module Pdfrb
|
|
|
40
41
|
def os2_table; table("OS/2"); end
|
|
41
42
|
def glyf_table; table("glyf"); end
|
|
42
43
|
def loca_table; table("loca"); end
|
|
44
|
+
def kern_table; table("kern"); end
|
|
43
45
|
|
|
44
46
|
# Parsed-table accessors. Lazy and memoised on the instance.
|
|
45
47
|
def head; @head ||= Head.new(head_table); end
|
|
48
|
+
|
|
49
|
+
def maxp; @maxp ||= Maxp.new(maxp_table); end
|
|
50
|
+
def post; @post ||= Post.new(post_table); end
|
|
51
|
+
def name_table_parsed; @name_table_parsed ||= Name.new(name_table); end
|
|
52
|
+
def loca_parsed; @loca_parsed ||= Loca.new(loca_table, long_format: head.long_loca?, num_glyphs: maxp.num_glyphs); end
|
|
53
|
+
def glyf_parsed; @glyf_parsed ||= Glyf.new(glyf_table, loca_parsed); end
|
|
54
|
+
def kern_parsed; @kern_parsed ||= Kern.new(kern_table); end
|
|
46
55
|
def hhea; @hhea ||= Hhea.new(hhea_table); end
|
|
47
56
|
def os2; @os2 ||= OS2.new(os2_table); end
|
|
48
57
|
def cmap; @cmap ||= Cmap.new(cmap_table); end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
module TrueType
|
|
6
|
+
class Glyf
|
|
7
|
+
attr_reader :data, :loca
|
|
8
|
+
|
|
9
|
+
def initialize(data, loca = nil)
|
|
10
|
+
@data = data
|
|
11
|
+
@loca = loca
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def glyph_data(glyph_id)
|
|
15
|
+
return nil unless @data && @loca
|
|
16
|
+
return nil if glyph_id >= @loca.offsets.length - 1
|
|
17
|
+
|
|
18
|
+
offset = @loca.glyph_offset(glyph_id)
|
|
19
|
+
length = @loca.glyph_length(glyph_id)
|
|
20
|
+
return nil if offset.nil? || length.zero?
|
|
21
|
+
|
|
22
|
+
@data.byteslice(offset, length)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def glyph_header(glyph_id)
|
|
26
|
+
g = glyph_data(glyph_id)
|
|
27
|
+
return nil unless g && g.bytesize >= 10
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
number_of_contours: s16(g, 0),
|
|
31
|
+
x_min: s16(g, 2),
|
|
32
|
+
y_min: s16(g, 4),
|
|
33
|
+
x_max: s16(g, 6),
|
|
34
|
+
y_max: s16(g, 8),
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def composite?(glyph_id)
|
|
39
|
+
h = glyph_header(glyph_id)
|
|
40
|
+
h && h[:number_of_contours].negative?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def empty?(glyph_id)
|
|
44
|
+
length = @loca&.glyph_length(glyph_id) || 0
|
|
45
|
+
length.zero?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def component_glyphs(glyph_id)
|
|
49
|
+
return [] unless composite?(glyph_id)
|
|
50
|
+
|
|
51
|
+
g = glyph_data(glyph_id)
|
|
52
|
+
return [] unless g
|
|
53
|
+
|
|
54
|
+
components = []
|
|
55
|
+
offset = 10
|
|
56
|
+
loop do
|
|
57
|
+
break if offset + 4 > g.bytesize
|
|
58
|
+
|
|
59
|
+
flags = u16(g, offset)
|
|
60
|
+
glyph_index = u16(g, offset + 2)
|
|
61
|
+
components << glyph_index
|
|
62
|
+
offset += 4
|
|
63
|
+
|
|
64
|
+
offset += 4 if flags & 0x0001 != 0
|
|
65
|
+
offset += 2 if flags & 0x0002 != 0
|
|
66
|
+
break if flags.nobits?(0x0020)
|
|
67
|
+
end
|
|
68
|
+
components
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def u16(d, o); (d.getbyte(o) << 8) | d.getbyte(o + 1); end
|
|
74
|
+
|
|
75
|
+
def s16(d, o)
|
|
76
|
+
v = u16(d, o)
|
|
77
|
+
v >= 32768 ? v - 65536 : v
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
module TrueType
|
|
6
|
+
class Kern
|
|
7
|
+
attr_reader :pairs
|
|
8
|
+
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@pairs = {}
|
|
11
|
+
return unless data && data.bytesize >= 4
|
|
12
|
+
|
|
13
|
+
version = u16(data, 0)
|
|
14
|
+
n_tables = u16(data, 2)
|
|
15
|
+
|
|
16
|
+
offset = 4
|
|
17
|
+
n_tables.times do
|
|
18
|
+
break if offset + 6 > data.bytesize
|
|
19
|
+
|
|
20
|
+
u16(data, offset)
|
|
21
|
+
sub_length = u16(data, offset + 2)
|
|
22
|
+
coverage = u16(data, offset + 4)
|
|
23
|
+
|
|
24
|
+
if version.zero? && coverage & 0x0001 != 0
|
|
25
|
+
n_pairs = u16(data, offset + 6)
|
|
26
|
+
pair_offset = offset + 14
|
|
27
|
+
|
|
28
|
+
n_pairs.times do |_p|
|
|
29
|
+
break if pair_offset + 6 > data.bytesize
|
|
30
|
+
|
|
31
|
+
left = u16(data, pair_offset)
|
|
32
|
+
right = u16(data, pair_offset + 2)
|
|
33
|
+
value = s16(data, pair_offset + 4)
|
|
34
|
+
@pairs[[left, right]] = value
|
|
35
|
+
pair_offset += 6
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
offset += sub_length
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def kerning(left_glyph, right_glyph)
|
|
44
|
+
@pairs[[left_glyph, right_glyph]] || 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def u16(d, o); (d.getbyte(o) << 8) | d.getbyte(o + 1); end
|
|
50
|
+
|
|
51
|
+
def s16(d, o)
|
|
52
|
+
v = u16(d, o)
|
|
53
|
+
v >= 32768 ? v - 65536 : v
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
module TrueType
|
|
6
|
+
class Loca
|
|
7
|
+
attr_reader :offsets
|
|
8
|
+
|
|
9
|
+
def initialize(data, long_format: false, num_glyphs: 0)
|
|
10
|
+
@offsets = []
|
|
11
|
+
return unless data
|
|
12
|
+
|
|
13
|
+
count = num_glyphs + 1
|
|
14
|
+
count.times do |i|
|
|
15
|
+
@offsets << if long_format
|
|
16
|
+
u32(data, i * 4)
|
|
17
|
+
else
|
|
18
|
+
(u16(data, i * 2) * 2)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def glyph_offset(index)
|
|
24
|
+
return nil if index.nil? || index >= @offsets.length
|
|
25
|
+
|
|
26
|
+
@offsets[index]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def glyph_length(index)
|
|
30
|
+
return 0 if index.nil? || index + 1 >= @offsets.length
|
|
31
|
+
|
|
32
|
+
@offsets[index + 1] - @offsets[index]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def u16(data, off); (data.getbyte(off) << 8) | data.getbyte(off + 1); end
|
|
38
|
+
def u32(data, off); (data.getbyte(off) << 24) | (data.getbyte(off + 1) << 16) | (data.getbyte(off + 2) << 8) | data.getbyte(off + 3); end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
module TrueType
|
|
6
|
+
class Maxp
|
|
7
|
+
attr_reader :version, :num_glyphs, :max_points, :max_contours,
|
|
8
|
+
:max_composite_points, :max_composite_contours,
|
|
9
|
+
:max_zones, :max_twilight_points, :max_storage,
|
|
10
|
+
:max_function_defs, :max_instruction_defs,
|
|
11
|
+
:max_stack_elements, :max_size_of_instructions,
|
|
12
|
+
:max_component_elements, :max_component_depth
|
|
13
|
+
|
|
14
|
+
def initialize(data)
|
|
15
|
+
return unless data && data.bytesize >= 6
|
|
16
|
+
|
|
17
|
+
@version = data.bytes[0, 4].pack("C*").unpack1("N")
|
|
18
|
+
@num_glyphs = u16(data, 4)
|
|
19
|
+
return unless @version == 0x00010000 && data.bytesize >= 32
|
|
20
|
+
|
|
21
|
+
@max_points = u16(data, 6)
|
|
22
|
+
@max_contours = u16(data, 8)
|
|
23
|
+
@max_composite_points = u16(data, 10)
|
|
24
|
+
@max_composite_contours = u16(data, 12)
|
|
25
|
+
@max_zones = u16(data, 14)
|
|
26
|
+
@max_twilight_points = u16(data, 16)
|
|
27
|
+
@max_storage = u16(data, 18)
|
|
28
|
+
@max_function_defs = u16(data, 20)
|
|
29
|
+
@max_instruction_defs = u16(data, 22)
|
|
30
|
+
@max_stack_elements = u16(data, 24)
|
|
31
|
+
@max_size_of_instructions = u16(data, 26)
|
|
32
|
+
@max_component_elements = u16(data, 28)
|
|
33
|
+
@max_component_depth = u16(data, 30)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def u16(data, off)
|
|
39
|
+
(data.getbyte(off) << 8) | data.getbyte(off + 1)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Pdfrb
|
|
4
|
+
module Font
|
|
5
|
+
module TrueType
|
|
6
|
+
class Name
|
|
7
|
+
attr_reader :format, :count, :records
|
|
8
|
+
|
|
9
|
+
def initialize(data)
|
|
10
|
+
@records = {}
|
|
11
|
+
return unless data && data.bytesize >= 6
|
|
12
|
+
|
|
13
|
+
@format = u16(data, 0)
|
|
14
|
+
@count = u16(data, 2)
|
|
15
|
+
string_offset = u16(data, 4)
|
|
16
|
+
|
|
17
|
+
@count.times do |i|
|
|
18
|
+
offset = 6 + (i * 12)
|
|
19
|
+
break if offset + 12 > data.bytesize
|
|
20
|
+
|
|
21
|
+
platform_id = u16(data, offset)
|
|
22
|
+
u16(data, offset + 2)
|
|
23
|
+
_lang_id = u16(data, offset + 4)
|
|
24
|
+
name_id = u16(data, offset + 6)
|
|
25
|
+
length = u16(data, offset + 8)
|
|
26
|
+
str_offset = u16(data, offset + 10)
|
|
27
|
+
|
|
28
|
+
next unless [1, 3].include?(platform_id)
|
|
29
|
+
|
|
30
|
+
raw = data.byteslice(string_offset + str_offset, length)
|
|
31
|
+
next unless raw
|
|
32
|
+
|
|
33
|
+
str = if platform_id == 3
|
|
34
|
+
raw.bytes.each_slice(2).map { |b| (b[0] << 8) | (b[1] || 0) }.pack("U*")
|
|
35
|
+
else
|
|
36
|
+
raw.force_encoding("UTF-8")
|
|
37
|
+
end
|
|
38
|
+
@records[name_id] = str
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def family; @records[1] || @records[16]; end
|
|
43
|
+
def subfamily; @records[2] || @records[17]; end
|
|
44
|
+
def ps_name; @records[6]; end
|
|
45
|
+
def full_name; @records[4]; end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def u16(data, off); (data.getbyte(off) << 8) | data.getbyte(off + 1); end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|