hexapdf 0.46.0 → 1.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/CHANGELOG.md +342 -16
- data/LICENSE +1 -1
- data/README.md +9 -8
- data/examples/009-text_layouter_alignment.rb +4 -0
- data/examples/010-text_layouter_inline_boxes.rb +4 -0
- data/examples/011-text_layouter_line_wrapping.rb +4 -0
- data/examples/012-text_layouter_styling.rb +9 -4
- data/examples/013-text_layouter_shapes.rb +5 -0
- data/examples/015-boxes.rb +3 -0
- data/examples/016-frame_automatic_box_placement.rb +3 -0
- data/examples/017-frame_text_flow.rb +3 -0
- data/examples/022-outline.rb +5 -1
- data/examples/{028-frame_mask_mode.rb → 028-composer_mask_mode.rb} +3 -3
- data/lib/hexapdf/cli/batch.rb +1 -1
- data/lib/hexapdf/cli/command.rb +65 -65
- data/lib/hexapdf/cli/debug_info.rb +98 -0
- data/lib/hexapdf/cli/files.rb +1 -1
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +11 -6
- data/lib/hexapdf/cli/image2pdf.rb +1 -1
- data/lib/hexapdf/cli/images.rb +19 -4
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +24 -8
- data/lib/hexapdf/cli/merge.rb +1 -1
- data/lib/hexapdf/cli/modify.rb +1 -2
- data/lib/hexapdf/cli/optimize.rb +6 -6
- data/lib/hexapdf/cli/split.rb +1 -1
- data/lib/hexapdf/cli/usage.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +1 -1
- data/lib/hexapdf/cli.rb +20 -2
- data/lib/hexapdf/composer.rb +22 -1
- data/lib/hexapdf/configuration.rb +56 -1
- data/lib/hexapdf/content/canvas.rb +1 -1
- data/lib/hexapdf/content/canvas_composer.rb +1 -1
- data/lib/hexapdf/content/color_space.rb +1 -1
- data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +2 -2
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/content/parser.rb +22 -23
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +1 -1
- data/lib/hexapdf/data_dir.rb +1 -1
- data/lib/hexapdf/dictionary.rb +8 -2
- data/lib/hexapdf/dictionary_fields.rb +2 -2
- data/lib/hexapdf/digital_signature/cms_handler.rb +19 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +1 -1
- data/lib/hexapdf/digital_signature/signature.rb +2 -2
- data/lib/hexapdf/digital_signature/signatures.rb +1 -1
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +3 -3
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -2
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +25 -5
- data/lib/hexapdf/digital_signature/signing.rb +1 -1
- data/lib/hexapdf/digital_signature/verification_result.rb +1 -1
- data/lib/hexapdf/digital_signature.rb +1 -1
- data/lib/hexapdf/document/annotations.rb +220 -0
- data/lib/hexapdf/document/destinations.rb +1 -1
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/document/layout.rb +95 -16
- data/lib/hexapdf/document/metadata.rb +11 -4
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/document.rb +52 -9
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +3 -3
- data/lib/hexapdf/encryption/fast_aes.rb +1 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +4 -2
- data/lib/hexapdf/encryption/standard_security_handler.rb +40 -29
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/error.rb +12 -4
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/crypt.rb +1 -1
- data/lib/hexapdf/filter/encryption.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +59 -5
- data/lib/hexapdf/font/cmap.rb +18 -7
- data/lib/hexapdf/font/encoding/base.rb +28 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +1 -1
- data/lib/hexapdf/font/true_type/builder.rb +1 -1
- data/lib/hexapdf/font/true_type/font.rb +1 -1
- data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
- data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
- data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
- data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
- data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
- data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
- data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
- data/lib/hexapdf/font/true_type/table/name.rb +1 -1
- data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
- data/lib/hexapdf/font/true_type/table/post.rb +1 -1
- data/lib/hexapdf/font/true_type/table.rb +7 -2
- data/lib/hexapdf/font/true_type.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +51 -16
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
- data/lib/hexapdf/font/type1.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +3 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
- data/lib/hexapdf/font_loader/from_file.rb +1 -1
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/font_loader/variant_from_name.rb +1 -1
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +1 -1
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +2 -2
- data/lib/hexapdf/layout/box.rb +6 -1
- data/lib/hexapdf/layout/box_fitter.rb +1 -1
- data/lib/hexapdf/layout/column_box.rb +1 -1
- data/lib/hexapdf/layout/container_box.rb +64 -29
- data/lib/hexapdf/layout/frame.rb +1 -1
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/inline_box.rb +1 -1
- data/lib/hexapdf/layout/line.rb +1 -1
- data/lib/hexapdf/layout/list_box.rb +1 -1
- data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
- data/lib/hexapdf/layout/page_style.rb +1 -1
- data/lib/hexapdf/layout/style.rb +133 -22
- data/lib/hexapdf/layout/table_box.rb +86 -14
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +13 -2
- data/lib/hexapdf/layout/text_layouter.rb +1 -1
- data/lib/hexapdf/layout/text_shaper.rb +1 -1
- data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
- data/lib/hexapdf/layout.rb +1 -1
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +4 -4
- data/lib/hexapdf/parser.rb +36 -7
- data/lib/hexapdf/pdf_array.rb +26 -4
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +2 -2
- data/lib/hexapdf/revision.rb +7 -3
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/serializer.rb +8 -8
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/merge_acro_form.rb +164 -0
- data/lib/hexapdf/task/optimize.rb +5 -5
- data/lib/hexapdf/task/pdfa.rb +1 -1
- data/lib/hexapdf/task.rb +2 -1
- data/lib/hexapdf/test_utils.rb +3 -2
- data/lib/hexapdf/tokenizer.rb +52 -44
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +66 -13
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +6 -2
- data/lib/hexapdf/type/acro_form/form.rb +23 -32
- data/lib/hexapdf/type/acro_form/java_script_actions.rb +10 -3
- data/lib/hexapdf/type/acro_form/signature_field.rb +19 -8
- data/lib/hexapdf/type/acro_form/text_field.rb +10 -3
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +13 -5
- data/lib/hexapdf/type/acro_form.rb +1 -1
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +2 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +2 -1
- data/lib/hexapdf/type/actions/launch.rb +6 -2
- data/lib/hexapdf/type/actions/set_ocg_state.rb +1 -1
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +78 -3
- data/lib/hexapdf/type/annotations/appearance_generator.rb +426 -0
- data/lib/hexapdf/type/annotations/border_effect.rb +99 -0
- data/lib/hexapdf/type/annotations/border_styling.rb +160 -0
- data/lib/hexapdf/type/annotations/circle.rb +65 -0
- data/lib/hexapdf/type/annotations/interior_color.rb +84 -0
- data/lib/hexapdf/type/annotations/line.rb +334 -0
- data/lib/hexapdf/type/annotations/line_ending_styling.rb +208 -0
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +15 -3
- data/lib/hexapdf/type/annotations/polygon.rb +64 -0
- data/lib/hexapdf/type/annotations/polygon_polyline.rb +109 -0
- data/lib/hexapdf/type/annotations/polyline.rb +64 -0
- data/lib/hexapdf/type/annotations/square.rb +65 -0
- data/lib/hexapdf/type/annotations/square_circle.rb +77 -0
- data/lib/hexapdf/type/annotations/text.rb +1 -1
- data/lib/hexapdf/type/annotations/widget.rb +56 -118
- data/lib/hexapdf/type/annotations.rb +13 -1
- data/lib/hexapdf/type/catalog.rb +5 -2
- data/lib/hexapdf/type/cid_font.rb +6 -3
- data/lib/hexapdf/type/cmap.rb +58 -0
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +18 -15
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_descriptor.rb +5 -4
- data/lib/hexapdf/type/font_simple.rb +4 -2
- data/lib/hexapdf/type/font_true_type.rb +3 -1
- data/lib/hexapdf/type/font_type0.rb +2 -2
- data/lib/hexapdf/type/font_type1.rb +19 -1
- data/lib/hexapdf/type/font_type3.rb +1 -2
- data/lib/hexapdf/type/form.rb +8 -5
- data/lib/hexapdf/type/graphics_state_parameter.rb +8 -5
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +9 -5
- data/lib/hexapdf/type/info.rb +3 -3
- data/lib/hexapdf/type/mark_information.rb +3 -3
- data/lib/hexapdf/type/marked_content_reference.rb +59 -0
- data/lib/hexapdf/type/measure.rb +57 -0
- data/lib/hexapdf/type/metadata.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/namespace.rb +57 -0
- data/lib/hexapdf/type/object_reference.rb +57 -0
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +2 -2
- data/lib/hexapdf/type/optional_content_group.rb +1 -1
- data/lib/hexapdf/type/optional_content_membership.rb +2 -2
- data/lib/hexapdf/type/optional_content_properties.rb +1 -1
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/output_intent.rb +1 -1
- data/lib/hexapdf/type/page.rb +6 -4
- data/lib/hexapdf/type/page_label.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +13 -9
- data/lib/hexapdf/type/struct_elem.rb +72 -0
- data/lib/hexapdf/type/struct_tree_root.rb +64 -0
- data/lib/hexapdf/type/trailer.rb +1 -1
- data/lib/hexapdf/type/viewer_preferences.rb +5 -4
- data/lib/hexapdf/type/xref_stream.rb +1 -1
- data/lib/hexapdf/type.rb +8 -1
- data/lib/hexapdf/utils/bit_field.rb +1 -1
- data/lib/hexapdf/utils/bit_stream.rb +1 -1
- data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
- data/lib/hexapdf/utils/lru_cache.rb +1 -1
- data/lib/hexapdf/utils/math_helpers.rb +1 -1
- data/lib/hexapdf/utils/object_hash.rb +1 -1
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +17 -4
- data/lib/hexapdf/utils.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +3 -2
- data/lib/hexapdf/xref_section.rb +25 -6
- data/lib/hexapdf.rb +1 -1
- data/test/data/standard-security-handler/bothpwd-aes-256bit-V5-R5.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-aes-256bit-V5-R5.pdf +44 -0
- data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5-R5.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-256bit-V5-R5.pdf +0 -0
- data/test/hexapdf/common_tokenizer_tests.rb +7 -7
- data/test/hexapdf/content/test_graphics_state.rb +2 -3
- data/test/hexapdf/content/test_operator.rb +4 -5
- data/test/hexapdf/digital_signature/common.rb +6 -1
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +6 -1
- data/test/hexapdf/digital_signature/signing/test_timestamp_handler.rb +12 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +25 -15
- data/test/hexapdf/digital_signature/test_handler.rb +2 -3
- data/test/hexapdf/digital_signature/test_pkcs1_handler.rb +1 -2
- data/test/hexapdf/digital_signature/test_signature.rb +7 -0
- data/test/hexapdf/digital_signature/test_signatures.rb +12 -7
- data/test/hexapdf/document/test_annotations.rb +75 -0
- data/test/hexapdf/document/test_layout.rb +38 -10
- data/test/hexapdf/document/test_metadata.rb +13 -1
- data/test/hexapdf/encryption/common.rb +1 -1
- data/test/hexapdf/encryption/test_aes.rb +1 -1
- data/test/hexapdf/encryption/test_arc4.rb +2 -2
- data/test/hexapdf/encryption/test_security_handler.rb +8 -6
- data/test/hexapdf/encryption/test_standard_security_handler.rb +7 -3
- data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
- data/test/hexapdf/filter/test_flate_decode.rb +2 -3
- data/test/hexapdf/font/cmap/test_writer.rb +73 -16
- data/test/hexapdf/font/encoding/test_base.rb +20 -0
- data/test/hexapdf/font/encoding/test_glyph_list.rb +1 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +31 -5
- data/test/hexapdf/font/test_type1_wrapper.rb +8 -1
- data/test/hexapdf/font/true_type/test_table.rb +12 -0
- data/test/hexapdf/layout/test_box.rb +8 -2
- data/test/hexapdf/layout/test_container_box.rb +34 -6
- data/test/hexapdf/layout/test_list_box.rb +7 -7
- data/test/hexapdf/layout/test_page_style.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +46 -12
- data/test/hexapdf/layout/test_table_box.rb +66 -16
- data/test/hexapdf/layout/test_text_box.rb +0 -6
- data/test/hexapdf/layout/test_text_fragment.rb +3 -3
- data/test/hexapdf/layout/test_text_layouter.rb +4 -2
- data/test/hexapdf/task/test_merge_acro_form.rb +104 -0
- data/test/hexapdf/task/test_optimize.rb +3 -1
- data/test/hexapdf/test_composer.rb +15 -0
- data/test/hexapdf/test_dictionary.rb +15 -0
- data/test/hexapdf/test_dictionary_fields.rb +1 -0
- data/test/hexapdf/test_document.rb +26 -8
- data/test/hexapdf/test_filter.rb +1 -1
- data/test/hexapdf/test_importer.rb +7 -0
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_parser.rb +87 -18
- data/test/hexapdf/test_pdf_array.rb +36 -3
- data/test/hexapdf/test_revision.rb +27 -6
- data/test/hexapdf/test_revisions.rb +1 -1
- data/test/hexapdf/test_serializer.rb +4 -4
- data/test/hexapdf/test_stream.rb +1 -2
- data/test/hexapdf/test_tokenizer.rb +1 -1
- data/test/hexapdf/test_writer.rb +22 -8
- data/test/hexapdf/test_xref_section.rb +15 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +118 -26
- data/test/hexapdf/type/acro_form/test_button_field.rb +7 -6
- data/test/hexapdf/type/acro_form/test_field.rb +10 -0
- data/test/hexapdf/type/acro_form/test_form.rb +32 -9
- data/test/hexapdf/type/acro_form/test_java_script_actions.rb +21 -0
- data/test/hexapdf/type/acro_form/test_signature_field.rb +3 -1
- data/test/hexapdf/type/acro_form/test_text_field.rb +7 -1
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +14 -1
- data/test/hexapdf/type/actions/test_launch.rb +6 -2
- data/test/hexapdf/type/annotations/test_appearance_generator.rb +608 -0
- data/test/hexapdf/type/annotations/test_border_effect.rb +59 -0
- data/test/hexapdf/type/annotations/test_border_styling.rb +114 -0
- data/test/hexapdf/type/annotations/test_interior_color.rb +37 -0
- data/test/hexapdf/type/annotations/test_line.rb +144 -0
- data/test/hexapdf/type/annotations/test_line_ending_styling.rb +42 -0
- data/test/hexapdf/type/annotations/test_polygon_polyline.rb +29 -0
- data/test/hexapdf/type/annotations/test_widget.rb +47 -81
- data/test/hexapdf/type/test_annotation.rb +58 -0
- data/test/hexapdf/type/test_font_type1.rb +20 -1
- data/test/hexapdf/type/test_form.rb +7 -1
- data/test/hexapdf/type/test_image.rb +1 -1
- data/test/hexapdf/type/test_page.rb +7 -1
- data/test/hexapdf/type/test_page_tree_node.rb +2 -2
- data/test/hexapdf/type/test_resources.rb +3 -1
- data/test/hexapdf/utils/test_sorted_tree_node.rb +18 -7
- data/test/test_helper.rb +7 -0
- metadata +69 -9
data/lib/hexapdf/document.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -43,6 +43,8 @@ require 'hexapdf/reference'
|
|
|
43
43
|
require 'hexapdf/object'
|
|
44
44
|
require 'hexapdf/pdf_array'
|
|
45
45
|
require 'hexapdf/stream'
|
|
46
|
+
require 'hexapdf/name_tree_node'
|
|
47
|
+
require 'hexapdf/number_tree_node'
|
|
46
48
|
require 'hexapdf/revisions'
|
|
47
49
|
require 'hexapdf/type'
|
|
48
50
|
require 'hexapdf/task'
|
|
@@ -121,6 +123,7 @@ module HexaPDF
|
|
|
121
123
|
autoload(:Destinations, 'hexapdf/document/destinations')
|
|
122
124
|
autoload(:Layout, 'hexapdf/document/layout')
|
|
123
125
|
autoload(:Metadata, 'hexapdf/document/metadata')
|
|
126
|
+
autoload(:Annotations, 'hexapdf/document/annotations')
|
|
124
127
|
|
|
125
128
|
# :call-seq:
|
|
126
129
|
# Document.open(filename, **docargs) -> doc
|
|
@@ -537,6 +540,12 @@ module HexaPDF
|
|
|
537
540
|
@destinations ||= Destinations.new(self)
|
|
538
541
|
end
|
|
539
542
|
|
|
543
|
+
# Returns the Annotations object that provides convenience methods for working with annotation
|
|
544
|
+
# objects.
|
|
545
|
+
def annotations
|
|
546
|
+
@annotations ||= Annotations.new(self)
|
|
547
|
+
end
|
|
548
|
+
|
|
540
549
|
# Returns the Layout object that provides convenience methods for working with the
|
|
541
550
|
# HexaPDF::Layout classes for document layout.
|
|
542
551
|
def layout
|
|
@@ -724,14 +733,25 @@ module HexaPDF
|
|
|
724
733
|
end
|
|
725
734
|
|
|
726
735
|
# :call-seq:
|
|
727
|
-
# doc.write(filename, incremental: false, validate: true, update_fields: true, optimize: false)
|
|
728
|
-
# doc.write(io, incremental: false, validate: true, update_fields: true, optimize: false)
|
|
736
|
+
# doc.write(filename, incremental: false, validate: true, update_fields: true, optimize: false, compact: true) -> [start_xref, section]
|
|
737
|
+
# doc.write(io, incremental: false, validate: true, update_fields: true, optimize: false, compact: true) -> [start_xref, section]
|
|
729
738
|
#
|
|
730
|
-
# Writes the document to the given file (in case +io+ is a String) or IO stream.
|
|
739
|
+
# Writes the document to the given file (in case +io+ is a String) or IO stream. Returns the
|
|
740
|
+
# file position of the start of the last cross-reference section and the last XRefSection object
|
|
741
|
+
# written.
|
|
731
742
|
#
|
|
732
743
|
# Before the document is written, it is validated using #validate and an error is raised if the
|
|
733
744
|
# document is not valid. However, this step can be skipped if needed.
|
|
734
745
|
#
|
|
746
|
+
# The method dispatches two messages:
|
|
747
|
+
#
|
|
748
|
+
# :complete_objects::
|
|
749
|
+
# This message is dispatched before anything is done and should be used to finalize objects.
|
|
750
|
+
#
|
|
751
|
+
# :before_write::
|
|
752
|
+
# This message is dispatched directly before the document gets serialized and allows, for
|
|
753
|
+
# example, overriding automatic HexaPDF changes (e.g. forcefully setting a document version).
|
|
754
|
+
#
|
|
735
755
|
# Options:
|
|
736
756
|
#
|
|
737
757
|
# incremental::
|
|
@@ -751,7 +771,20 @@ module HexaPDF
|
|
|
751
771
|
# optimize::
|
|
752
772
|
# Optimize the file size by using object and cross-reference streams. This will raise the PDF
|
|
753
773
|
# version to at least 1.5.
|
|
754
|
-
|
|
774
|
+
#
|
|
775
|
+
# compact::
|
|
776
|
+
# Compact the document by reducing it to a single revision and removing null and unused
|
|
777
|
+
# objects.
|
|
778
|
+
#
|
|
779
|
+
# The initial revision of a document has to contain objects with continuous numbering. If some
|
|
780
|
+
# object numbers refer to free entries, other PDF libraries/viewers might not work
|
|
781
|
+
# correctly. So continuous object numbers are assigned to stay compliant with the
|
|
782
|
+
# specification.
|
|
783
|
+
#
|
|
784
|
+
# Only change this argument to +false+ if you run the optimization task with 'compact: true'
|
|
785
|
+
# beforehand or if you know exactly what you do and what not compacting implies.
|
|
786
|
+
def write(file_or_io, incremental: false, validate: true, update_fields: true, optimize: false,
|
|
787
|
+
compact: true)
|
|
755
788
|
if update_fields
|
|
756
789
|
trailer.update_id
|
|
757
790
|
if @metadata
|
|
@@ -770,10 +803,11 @@ module HexaPDF
|
|
|
770
803
|
end
|
|
771
804
|
end
|
|
772
805
|
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
806
|
+
optimize_opts = {}
|
|
807
|
+
optimize_opts[:object_streams] = :generate if optimize
|
|
808
|
+
optimize_opts[:compact] = true if compact && !incremental
|
|
809
|
+
task(:optimize, **optimize_opts) unless optimize_opts.empty?
|
|
810
|
+
self.version = '1.5' if version < '1.5' if optimize
|
|
777
811
|
|
|
778
812
|
dispatch_message(:before_write)
|
|
779
813
|
|
|
@@ -784,6 +818,15 @@ module HexaPDF
|
|
|
784
818
|
end
|
|
785
819
|
end
|
|
786
820
|
|
|
821
|
+
# Writes the document to a string and returns the string.
|
|
822
|
+
#
|
|
823
|
+
# See #write for further information and details on the available arguments.
|
|
824
|
+
def write_to_string(**args)
|
|
825
|
+
io = StringIO.new(''.b)
|
|
826
|
+
write(io, **args)
|
|
827
|
+
io.string
|
|
828
|
+
end
|
|
829
|
+
|
|
787
830
|
def inspect #:nodoc:
|
|
788
831
|
"<#{self.class.name}:#{object_id}>"
|
|
789
832
|
end
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -66,14 +66,14 @@ module HexaPDF
|
|
|
66
66
|
# Encrypts the given +data+ with the +key+.
|
|
67
67
|
#
|
|
68
68
|
# See: PDF2.0 s7.6.3
|
|
69
|
-
def encrypt(key, data)
|
|
69
|
+
def encrypt(key, data, &_block)
|
|
70
70
|
new(key).process(data)
|
|
71
71
|
end
|
|
72
72
|
alias decrypt encrypt
|
|
73
73
|
|
|
74
74
|
# Returns a Fiber object that encrypts the data from the given source fiber with the
|
|
75
75
|
# +key+.
|
|
76
|
-
def encryption_fiber(key, source)
|
|
76
|
+
def encryption_fiber(key, source, &_block)
|
|
77
77
|
Fiber.new do
|
|
78
78
|
algorithm = new(key)
|
|
79
79
|
while source.alive? && (data = source.resume)
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -363,7 +363,9 @@ module HexaPDF
|
|
|
363
363
|
raise(HexaPDF::UnsupportedEncryptionError,
|
|
364
364
|
"Invalid key length #{key_length} specified")
|
|
365
365
|
end
|
|
366
|
-
|
|
366
|
+
# /Length should only be set for V=2 as per the spec. However, software like Adobe Reader
|
|
367
|
+
# fails if this is not set for V=5 or V=4.
|
|
368
|
+
dict[:Length] = key_length if dict[:V] == 5 || dict[:V] == 4 || dict[:V] == 2
|
|
367
369
|
|
|
368
370
|
if ![:aes, :arc4].include?(algorithm)
|
|
369
371
|
raise(HexaPDF::UnsupportedEncryptionError,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -106,6 +106,10 @@ module HexaPDF
|
|
|
106
106
|
# password is supplied. To open such an encrypted PDF file, the +decryption_opts+ provided to
|
|
107
107
|
# HexaPDF::Document.new needs to contain a :password key with the password.
|
|
108
108
|
#
|
|
109
|
+
# **Note**: While HexaPDF supports reading files encrypted with revision 5, it doesn't support
|
|
110
|
+
# writing such files. This is no problem in practice since revision 5 was an inofficial Adobe
|
|
111
|
+
# extension to PDF 1.7 and revision 6 specified in PDF 2.0 is practically the same.
|
|
112
|
+
#
|
|
109
113
|
# See: PDF2.0 s7.6.4
|
|
110
114
|
class StandardSecurityHandler < SecurityHandler
|
|
111
115
|
|
|
@@ -321,8 +325,13 @@ module HexaPDF
|
|
|
321
325
|
options.user_password = prepare_password(options.user_password)
|
|
322
326
|
options.owner_password = prepare_password(options.owner_password)
|
|
323
327
|
|
|
324
|
-
dict[:
|
|
325
|
-
|
|
328
|
+
if dict[:R] <= 4
|
|
329
|
+
dict[:O] = compute_o_field(options.owner_password, options.user_password)
|
|
330
|
+
dict[:U] = compute_u_field(options.user_password)
|
|
331
|
+
else
|
|
332
|
+
dict[:U] = compute_u_field(options.user_password)
|
|
333
|
+
dict[:O] = compute_o_field(options.owner_password, options.user_password)
|
|
334
|
+
end
|
|
326
335
|
|
|
327
336
|
if dict[:R] <= 4
|
|
328
337
|
encryption_key = compute_user_encryption_key(options.user_password)
|
|
@@ -340,13 +349,13 @@ module HexaPDF
|
|
|
340
349
|
# Uses the given password (or the default password if none given) to retrieve the encryption
|
|
341
350
|
# key.
|
|
342
351
|
#
|
|
343
|
-
# If the optional +check_permissions+ argument is +true+, the permissions for files
|
|
344
|
-
#
|
|
352
|
+
# If the optional +check_permissions+ argument is +true+, the permissions for files encrypted
|
|
353
|
+
# with revision 5 or 6 are checked. Otherwise, permission changes are ignored.
|
|
345
354
|
def prepare_decryption(password: '', check_permissions: true)
|
|
346
355
|
if dict[:Filter] != :Standard
|
|
347
356
|
raise(HexaPDF::UnsupportedEncryptionError,
|
|
348
357
|
"Invalid /Filter value #{dict[:Filter]} for standard security handler")
|
|
349
|
-
elsif ![2, 3, 4, 6].include?(dict[:R])
|
|
358
|
+
elsif ![2, 3, 4, 5, 6].include?(dict[:R])
|
|
350
359
|
raise(HexaPDF::UnsupportedEncryptionError,
|
|
351
360
|
"Invalid /R value #{dict[:R]} for standard security handler")
|
|
352
361
|
elsif dict[:R] <= 4 && !document.trailer[:ID].kind_of?(PDFArray)
|
|
@@ -369,7 +378,7 @@ module HexaPDF
|
|
|
369
378
|
raise HexaPDF::EncryptionError, "Invalid password specified"
|
|
370
379
|
end
|
|
371
380
|
|
|
372
|
-
check_perms_field(encryption_key) if check_permissions && dict[:R]
|
|
381
|
+
check_perms_field(encryption_key) if check_permissions && dict[:R] >= 5
|
|
373
382
|
|
|
374
383
|
encryption_key
|
|
375
384
|
end
|
|
@@ -396,8 +405,8 @@ module HexaPDF
|
|
|
396
405
|
# For revisions <= 4 this is the *only* way for generating the encryption key needed to
|
|
397
406
|
# encrypt or decrypt a file.
|
|
398
407
|
#
|
|
399
|
-
# For revision 6 the file encryption key is a string of random bytes that has been
|
|
400
|
-
# with the user password. If the password is the owner password,
|
|
408
|
+
# For revision 5 and 6 the file encryption key is a string of random bytes that has been
|
|
409
|
+
# encrypted with the user password. If the password is the owner password,
|
|
401
410
|
# #compute_owner_encryption_key has to be used instead.
|
|
402
411
|
#
|
|
403
412
|
# See: PDF2.0 s7.6.4.3.2 (algorithm 2), PDF2.0 s7.6.4.3.3 (algorithm 2.A (a)-(b),(e))
|
|
@@ -416,7 +425,7 @@ module HexaPDF
|
|
|
416
425
|
end
|
|
417
426
|
|
|
418
427
|
data[0, n]
|
|
419
|
-
elsif dict[:R]
|
|
428
|
+
elsif dict[:R] <= 6
|
|
420
429
|
key = compute_hash(password, dict[:U][40, 8])
|
|
421
430
|
aes_algorithm.new(key, "\0" * 16, :decrypt).process(dict[:UE])
|
|
422
431
|
end
|
|
@@ -427,15 +436,15 @@ module HexaPDF
|
|
|
427
436
|
# For revisions <= 4 this is done by first retrieving the user password through the use of
|
|
428
437
|
# the owner password and then using the #compute_user_encryption_key method.
|
|
429
438
|
#
|
|
430
|
-
# For
|
|
431
|
-
# with the owner password. If the password is the user password,
|
|
432
|
-
# has to be used.
|
|
439
|
+
# For revisions 5 and 6 the file encryption key is a string of random bytes that has been
|
|
440
|
+
# encrypted with the owner password. If the password is the user password,
|
|
441
|
+
# #compute_user_encryption_key has to be used.
|
|
433
442
|
#
|
|
434
443
|
# See: PDF2.0 s7.6.4.3.2 (algorithm 2.A (a)-(d))
|
|
435
444
|
def compute_owner_encryption_key(password)
|
|
436
445
|
if dict[:R] <= 4
|
|
437
446
|
compute_user_encryption_key(user_password_from_owner_password(password))
|
|
438
|
-
elsif dict[:R]
|
|
447
|
+
elsif dict[:R] <= 6
|
|
439
448
|
key = compute_hash(password, dict[:O][40, 8], dict[:U])
|
|
440
449
|
aes_algorithm.new(key, "\0" * 16, :decrypt).process(dict[:OE])
|
|
441
450
|
end
|
|
@@ -447,7 +456,7 @@ module HexaPDF
|
|
|
447
456
|
# the owner password. For revision 6 the /O value is a hash computed from the password and
|
|
448
457
|
# the /U value with added validation and key salts.
|
|
449
458
|
#
|
|
450
|
-
# *Attention*: If revision 6 is used, the /U value has to be computed and set before this
|
|
459
|
+
# *Attention*: If revision 5 or 6 is used, the /U value has to be computed and set before this
|
|
451
460
|
# method is used, otherwise the return value is incorrect!
|
|
452
461
|
#
|
|
453
462
|
# See: PDF2.0 s7.6.4.4.2 (algorithm 3), PDF2.0 s7.6.4.4.8 (algorithm 9 (a))
|
|
@@ -465,14 +474,14 @@ module HexaPDF
|
|
|
465
474
|
end
|
|
466
475
|
|
|
467
476
|
data
|
|
468
|
-
elsif dict[:R]
|
|
477
|
+
elsif dict[:R] <= 6
|
|
469
478
|
validation_salt = random_bytes(8)
|
|
470
479
|
key_salt = random_bytes(8)
|
|
471
480
|
compute_hash(owner_password, validation_salt, dict[:U]) << validation_salt << key_salt
|
|
472
481
|
end
|
|
473
482
|
end
|
|
474
483
|
|
|
475
|
-
# Computes the encryption dictionary's /OE (owner encryption key) value (for
|
|
484
|
+
# Computes the encryption dictionary's /OE (owner encryption key) value (for revisions 5 and 6
|
|
476
485
|
# only).
|
|
477
486
|
#
|
|
478
487
|
# Short explanation: Encrypts the file encryption key with a key based on the password and
|
|
@@ -487,7 +496,7 @@ module HexaPDF
|
|
|
487
496
|
# Computes the encryption dictionary's /U (user password) value.
|
|
488
497
|
#
|
|
489
498
|
# Short explanation: For revisions <= 4, the password padding string is encrypted with a key
|
|
490
|
-
# based on the user password. For
|
|
499
|
+
# based on the user password. For revisions 5 and 6 the /U value is a hash computed from the
|
|
491
500
|
# password with added validation and key salts.
|
|
492
501
|
#
|
|
493
502
|
# See: PDF2.0 s7.6.4.4.3 (algorithm 4 for R=2), PDF s7.6.4.4.4 (algorithm 5 for R=3 and R=4)
|
|
@@ -502,14 +511,14 @@ module HexaPDF
|
|
|
502
511
|
data = arc4_algorithm.encrypt(key, data)
|
|
503
512
|
19.times {|i| data = arc4_algorithm.encrypt(xor_key(key, i + 1), data) }
|
|
504
513
|
data << "hexapdfhexapdfhe"
|
|
505
|
-
elsif dict[:R]
|
|
514
|
+
elsif dict[:R] <= 6
|
|
506
515
|
validation_salt = random_bytes(8)
|
|
507
516
|
key_salt = random_bytes(8)
|
|
508
517
|
compute_hash(password, validation_salt) << validation_salt << key_salt
|
|
509
518
|
end
|
|
510
519
|
end
|
|
511
520
|
|
|
512
|
-
# Computes the encryption dictionary's /UE (user encryption key) value (for revision 6
|
|
521
|
+
# Computes the encryption dictionary's /UE (user encryption key) value (for revision 5 and 6
|
|
513
522
|
# only).
|
|
514
523
|
#
|
|
515
524
|
# Short explanation: Encrypts the file encryption key with a key based on the password and
|
|
@@ -521,7 +530,8 @@ module HexaPDF
|
|
|
521
530
|
aes_algorithm.new(key, "\0" * 16, :encrypt).process(file_encryption_key)
|
|
522
531
|
end
|
|
523
532
|
|
|
524
|
-
# Computes the encryption dictionary's /Perms (permissions) value (for
|
|
533
|
+
# Computes the encryption dictionary's /Perms (permissions) value (for revisions 5 and 6
|
|
534
|
+
# only).
|
|
525
535
|
#
|
|
526
536
|
# Uses /P and /EncryptMetadata values, so these have to be set beforehand.
|
|
527
537
|
#
|
|
@@ -543,7 +553,7 @@ module HexaPDF
|
|
|
543
553
|
compute_u_field(password) == dict[:U]
|
|
544
554
|
elsif dict[:R] <= 4
|
|
545
555
|
compute_u_field(password)[0, 16] == dict[:U][0, 16]
|
|
546
|
-
elsif dict[:R]
|
|
556
|
+
elsif dict[:R] <= 6
|
|
547
557
|
compute_hash(password, dict[:U][32, 8]) == dict[:U][0, 32]
|
|
548
558
|
end
|
|
549
559
|
end
|
|
@@ -554,14 +564,14 @@ module HexaPDF
|
|
|
554
564
|
def owner_password_valid?(password)
|
|
555
565
|
if dict[:R] <= 4
|
|
556
566
|
user_password_valid?(user_password_from_owner_password(password))
|
|
557
|
-
elsif dict[:R]
|
|
567
|
+
elsif dict[:R] <= 6
|
|
558
568
|
compute_hash(password, dict[:O][32, 8], dict[:U]) == dict[:O][0, 32]
|
|
559
569
|
end
|
|
560
570
|
end
|
|
561
571
|
|
|
562
572
|
# Checks if the decrypted /Perms entry matches the /P and /EncryptMetadata entries.
|
|
563
573
|
#
|
|
564
|
-
# This method can only be used for
|
|
574
|
+
# This method can only be used for revisions 5 and 6.
|
|
565
575
|
#
|
|
566
576
|
# See: PDF2.0 s7.6.4.4.12 (algorithm 13)
|
|
567
577
|
def check_perms_field(encryption_key)
|
|
@@ -596,17 +606,18 @@ module HexaPDF
|
|
|
596
606
|
end
|
|
597
607
|
|
|
598
608
|
# Computes a hash that is used extensively for all operations in security handlers of
|
|
599
|
-
# revision 6.
|
|
609
|
+
# revision 5 and 6.
|
|
600
610
|
#
|
|
601
611
|
# Note: The original input (as defined by the spec) is calculated as
|
|
602
612
|
# "#{password}#{salt}#{user_key}" where +user_key+ has to be empty when doing operations
|
|
603
613
|
# with the user password.
|
|
604
614
|
#
|
|
605
|
-
# See: PDF2.0 s7.6.4.3.4 (algorithm 2.B)
|
|
615
|
+
# See: PDF2.0 s7.6.4.3.4 (algorithm 2.B) and ADB Extension Level 3 s3.5.2
|
|
606
616
|
def compute_hash(password, salt, user_key = '')
|
|
607
617
|
k = Digest::SHA256.digest("#{password}#{salt}#{user_key}")
|
|
608
|
-
|
|
618
|
+
return k if dict[:R] == 5
|
|
609
619
|
|
|
620
|
+
e = ''
|
|
610
621
|
i = 0
|
|
611
622
|
while i < 64 || e.getbyte(-1) > i - 32
|
|
612
623
|
k1 = "#{password}#{k}#{user_key}" * 64
|
|
@@ -627,7 +638,7 @@ module HexaPDF
|
|
|
627
638
|
# * For revisions <= 4, the password is converted into ISO-8859-1 encoding, padded with
|
|
628
639
|
# PASSWORD_PADDING and truncated to a maximum of 32 bytes.
|
|
629
640
|
#
|
|
630
|
-
# * For revision 6 the password is converted into UTF-8 encoding that is normalized
|
|
641
|
+
# * For revision 5 and 6 the password is converted into UTF-8 encoding that is normalized
|
|
631
642
|
# according to the PDF2.0 specification.
|
|
632
643
|
#
|
|
633
644
|
# See: PDF2.0 s7.6.4.3.2 (algorithm 2 step a)),
|
|
@@ -636,7 +647,7 @@ module HexaPDF
|
|
|
636
647
|
if dict[:R] <= 4
|
|
637
648
|
password.to_s[0, 32].encode(Encoding::ISO_8859_1).force_encoding(Encoding::BINARY).
|
|
638
649
|
ljust(32, PASSWORD_PADDING)
|
|
639
|
-
elsif dict[:R]
|
|
650
|
+
elsif dict[:R] <= 6
|
|
640
651
|
password.to_s.encode(Encoding::UTF_8).force_encoding(Encoding::BINARY)[0, 127]
|
|
641
652
|
end
|
|
642
653
|
rescue Encoding::UndefinedConversionError => e
|
data/lib/hexapdf/encryption.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/error.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -94,9 +94,17 @@ module HexaPDF
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
def message # :nodoc:
|
|
97
|
-
"No glyph for #{glyph.str.inspect} in font '#{glyph.font_wrapper.wrapped_font.full_name}' " \
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
str = "No glyph for #{glyph.str.inspect} in font '#{glyph.font_wrapper.wrapped_font.full_name}' " \
|
|
98
|
+
"found. \n\n"
|
|
99
|
+
str << if glyph.font_wrapper.font_type == :Type1
|
|
100
|
+
"The used Type1 font only contains a very limited number of glyphs. TrueType " \
|
|
101
|
+
"fonts usually provide a much wider array of glyphs. Use the configuration option " \
|
|
102
|
+
"'font.map' to register appropriate font files. Also have a look at the " \
|
|
103
|
+
"'font.default' and 'font.fallback' options. "
|
|
104
|
+
else
|
|
105
|
+
"Maybe register another #{glyph.font_wrapper.font_type} font that contains the " \
|
|
106
|
+
"needed glyph and use it as fallback via the configuration option 'font.fallback'."
|
|
107
|
+
end
|
|
100
108
|
end
|
|
101
109
|
|
|
102
110
|
end
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/filter/crypt.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/filter.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C) 2014-
|
|
7
|
+
# Copyright (C) 2014-2025 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|