hexapdf 0.1.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 +7 -0
- data/CONTRIBUTERS +3 -0
- data/LICENSE +26 -0
- data/README.md +88 -0
- data/Rakefile +121 -0
- data/VERSION +1 -0
- data/agpl-3.0.txt +661 -0
- data/bin/hexapdf +6 -0
- data/data/hexapdf/afm/Courier-Bold.afm +342 -0
- data/data/hexapdf/afm/Courier-BoldOblique.afm +342 -0
- data/data/hexapdf/afm/Courier-Oblique.afm +342 -0
- data/data/hexapdf/afm/Courier.afm +342 -0
- data/data/hexapdf/afm/Helvetica-Bold.afm +2827 -0
- data/data/hexapdf/afm/Helvetica-BoldOblique.afm +2827 -0
- data/data/hexapdf/afm/Helvetica-Oblique.afm +3051 -0
- data/data/hexapdf/afm/Helvetica.afm +3051 -0
- data/data/hexapdf/afm/MustRead.html +1 -0
- data/data/hexapdf/afm/Symbol.afm +213 -0
- data/data/hexapdf/afm/Times-Bold.afm +2588 -0
- data/data/hexapdf/afm/Times-BoldItalic.afm +2384 -0
- data/data/hexapdf/afm/Times-Italic.afm +2667 -0
- data/data/hexapdf/afm/Times-Roman.afm +2419 -0
- data/data/hexapdf/afm/ZapfDingbats.afm +225 -0
- data/data/hexapdf/encoding/glyphlist.txt +4305 -0
- data/data/hexapdf/encoding/zapfdingbats.txt +225 -0
- data/examples/arc.rb +50 -0
- data/examples/graphics.rb +274 -0
- data/examples/hello_world.rb +16 -0
- data/examples/machupicchu.jpg +0 -0
- data/examples/merging.rb +24 -0
- data/examples/optimizing.rb +20 -0
- data/examples/show_char_bboxes.rb +55 -0
- data/examples/standard_pdf_fonts.rb +72 -0
- data/examples/truetype.rb +45 -0
- data/lib/hexapdf/cli/extract.rb +128 -0
- data/lib/hexapdf/cli/info.rb +121 -0
- data/lib/hexapdf/cli/inspect.rb +157 -0
- data/lib/hexapdf/cli/modify.rb +218 -0
- data/lib/hexapdf/cli.rb +121 -0
- data/lib/hexapdf/configuration.rb +392 -0
- data/lib/hexapdf/content/canvas.rb +1974 -0
- data/lib/hexapdf/content/color_space.rb +364 -0
- data/lib/hexapdf/content/graphic_object/arc.rb +267 -0
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +208 -0
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +173 -0
- data/lib/hexapdf/content/graphic_object.rb +81 -0
- data/lib/hexapdf/content/graphics_state.rb +579 -0
- data/lib/hexapdf/content/operator.rb +1072 -0
- data/lib/hexapdf/content/parser.rb +204 -0
- data/lib/hexapdf/content/processor.rb +451 -0
- data/lib/hexapdf/content/transformation_matrix.rb +172 -0
- data/lib/hexapdf/content.rb +47 -0
- data/lib/hexapdf/data_dir.rb +51 -0
- data/lib/hexapdf/dictionary.rb +303 -0
- data/lib/hexapdf/dictionary_fields.rb +382 -0
- data/lib/hexapdf/document.rb +589 -0
- data/lib/hexapdf/document_utils.rb +209 -0
- data/lib/hexapdf/encryption/aes.rb +206 -0
- data/lib/hexapdf/encryption/arc4.rb +93 -0
- data/lib/hexapdf/encryption/fast_aes.rb +79 -0
- data/lib/hexapdf/encryption/fast_arc4.rb +67 -0
- data/lib/hexapdf/encryption/identity.rb +63 -0
- data/lib/hexapdf/encryption/ruby_aes.rb +447 -0
- data/lib/hexapdf/encryption/ruby_arc4.rb +96 -0
- data/lib/hexapdf/encryption/security_handler.rb +494 -0
- data/lib/hexapdf/encryption/standard_security_handler.rb +616 -0
- data/lib/hexapdf/encryption.rb +94 -0
- data/lib/hexapdf/error.rb +73 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +160 -0
- data/lib/hexapdf/filter/ascii_hex_decode.rb +87 -0
- data/lib/hexapdf/filter/dct_decode.rb +57 -0
- data/lib/hexapdf/filter/encryption.rb +59 -0
- data/lib/hexapdf/filter/flate_decode.rb +93 -0
- data/lib/hexapdf/filter/jpx_decode.rb +56 -0
- data/lib/hexapdf/filter/lzw_decode.rb +191 -0
- data/lib/hexapdf/filter/predictor.rb +266 -0
- data/lib/hexapdf/filter/run_length_decode.rb +108 -0
- data/lib/hexapdf/filter.rb +176 -0
- data/lib/hexapdf/font/cmap/parser.rb +146 -0
- data/lib/hexapdf/font/cmap/writer.rb +176 -0
- data/lib/hexapdf/font/cmap.rb +90 -0
- data/lib/hexapdf/font/encoding/base.rb +77 -0
- data/lib/hexapdf/font/encoding/difference_encoding.rb +64 -0
- data/lib/hexapdf/font/encoding/glyph_list.rb +150 -0
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +221 -0
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +265 -0
- data/lib/hexapdf/font/encoding/standard_encoding.rb +205 -0
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +244 -0
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +280 -0
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +250 -0
- data/lib/hexapdf/font/encoding.rb +68 -0
- data/lib/hexapdf/font/true_type/font.rb +179 -0
- data/lib/hexapdf/font/true_type/table/cmap.rb +103 -0
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +384 -0
- data/lib/hexapdf/font/true_type/table/directory.rb +92 -0
- data/lib/hexapdf/font/true_type/table/glyf.rb +166 -0
- data/lib/hexapdf/font/true_type/table/head.rb +143 -0
- data/lib/hexapdf/font/true_type/table/hhea.rb +109 -0
- data/lib/hexapdf/font/true_type/table/hmtx.rb +79 -0
- data/lib/hexapdf/font/true_type/table/loca.rb +79 -0
- data/lib/hexapdf/font/true_type/table/maxp.rb +112 -0
- data/lib/hexapdf/font/true_type/table/name.rb +218 -0
- data/lib/hexapdf/font/true_type/table/os2.rb +200 -0
- data/lib/hexapdf/font/true_type/table/post.rb +230 -0
- data/lib/hexapdf/font/true_type/table.rb +155 -0
- data/lib/hexapdf/font/true_type.rb +48 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +240 -0
- data/lib/hexapdf/font/type1/afm_parser.rb +230 -0
- data/lib/hexapdf/font/type1/character_metrics.rb +67 -0
- data/lib/hexapdf/font/type1/font.rb +123 -0
- data/lib/hexapdf/font/type1/font_metrics.rb +117 -0
- data/lib/hexapdf/font/type1/pfb_parser.rb +71 -0
- data/lib/hexapdf/font/type1.rb +52 -0
- data/lib/hexapdf/font/type1_wrapper.rb +193 -0
- data/lib/hexapdf/font_loader/from_configuration.rb +70 -0
- data/lib/hexapdf/font_loader/standard14.rb +98 -0
- data/lib/hexapdf/font_loader.rb +85 -0
- data/lib/hexapdf/font_utils.rb +89 -0
- data/lib/hexapdf/image_loader/jpeg.rb +166 -0
- data/lib/hexapdf/image_loader/pdf.rb +89 -0
- data/lib/hexapdf/image_loader/png.rb +410 -0
- data/lib/hexapdf/image_loader.rb +68 -0
- data/lib/hexapdf/importer.rb +139 -0
- data/lib/hexapdf/name_tree_node.rb +78 -0
- data/lib/hexapdf/number_tree_node.rb +67 -0
- data/lib/hexapdf/object.rb +363 -0
- data/lib/hexapdf/parser.rb +349 -0
- data/lib/hexapdf/rectangle.rb +99 -0
- data/lib/hexapdf/reference.rb +98 -0
- data/lib/hexapdf/revision.rb +206 -0
- data/lib/hexapdf/revisions.rb +194 -0
- data/lib/hexapdf/serializer.rb +326 -0
- data/lib/hexapdf/stream.rb +279 -0
- data/lib/hexapdf/task/dereference.rb +109 -0
- data/lib/hexapdf/task/optimize.rb +230 -0
- data/lib/hexapdf/task.rb +68 -0
- data/lib/hexapdf/tokenizer.rb +406 -0
- data/lib/hexapdf/type/catalog.rb +107 -0
- data/lib/hexapdf/type/embedded_file.rb +87 -0
- data/lib/hexapdf/type/file_specification.rb +232 -0
- data/lib/hexapdf/type/font.rb +81 -0
- data/lib/hexapdf/type/font_descriptor.rb +109 -0
- data/lib/hexapdf/type/font_simple.rb +190 -0
- data/lib/hexapdf/type/font_true_type.rb +47 -0
- data/lib/hexapdf/type/font_type1.rb +162 -0
- data/lib/hexapdf/type/form.rb +103 -0
- data/lib/hexapdf/type/graphics_state_parameter.rb +79 -0
- data/lib/hexapdf/type/image.rb +73 -0
- data/lib/hexapdf/type/info.rb +70 -0
- data/lib/hexapdf/type/names.rb +69 -0
- data/lib/hexapdf/type/object_stream.rb +224 -0
- data/lib/hexapdf/type/page.rb +355 -0
- data/lib/hexapdf/type/page_tree_node.rb +269 -0
- data/lib/hexapdf/type/resources.rb +212 -0
- data/lib/hexapdf/type/trailer.rb +128 -0
- data/lib/hexapdf/type/viewer_preferences.rb +73 -0
- data/lib/hexapdf/type/xref_stream.rb +204 -0
- data/lib/hexapdf/type.rb +67 -0
- data/lib/hexapdf/utils/bit_field.rb +87 -0
- data/lib/hexapdf/utils/bit_stream.rb +148 -0
- data/lib/hexapdf/utils/lru_cache.rb +65 -0
- data/lib/hexapdf/utils/math_helpers.rb +55 -0
- data/lib/hexapdf/utils/object_hash.rb +130 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +93 -0
- data/lib/hexapdf/utils/sorted_tree_node.rb +339 -0
- data/lib/hexapdf/version.rb +39 -0
- data/lib/hexapdf/writer.rb +199 -0
- data/lib/hexapdf/xref_section.rb +152 -0
- data/lib/hexapdf.rb +34 -0
- data/man/man1/hexapdf.1 +249 -0
- data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
- data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
- data/test/data/fonts/Ubuntu-Title.ttf +0 -0
- data/test/data/images/cmyk.jpg +0 -0
- data/test/data/images/fillbytes.jpg +0 -0
- data/test/data/images/gray.jpg +0 -0
- data/test/data/images/greyscale-1bit.png +0 -0
- data/test/data/images/greyscale-2bit.png +0 -0
- data/test/data/images/greyscale-4bit.png +0 -0
- data/test/data/images/greyscale-8bit.png +0 -0
- data/test/data/images/greyscale-alpha-8bit.png +0 -0
- data/test/data/images/greyscale-trns-8bit.png +0 -0
- data/test/data/images/greyscale-with-gamma1.0.png +0 -0
- data/test/data/images/greyscale-with-gamma1.5.png +0 -0
- data/test/data/images/indexed-1bit.png +0 -0
- data/test/data/images/indexed-2bit.png +0 -0
- data/test/data/images/indexed-4bit.png +0 -0
- data/test/data/images/indexed-8bit.png +0 -0
- data/test/data/images/indexed-alpha-4bit.png +0 -0
- data/test/data/images/indexed-alpha-8bit.png +0 -0
- data/test/data/images/rgb.jpg +0 -0
- data/test/data/images/truecolour-8bit.png +0 -0
- data/test/data/images/truecolour-alpha-8bit.png +0 -0
- data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
- data/test/data/images/truecolour-srgb-8bit.png +0 -0
- data/test/data/minimal.pdf +44 -0
- data/test/data/standard-security-handler/README +9 -0
- data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
- data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
- data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
- data/test/hexapdf/common_tokenizer_tests.rb +204 -0
- data/test/hexapdf/content/common.rb +31 -0
- data/test/hexapdf/content/graphic_object/test_arc.rb +93 -0
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +91 -0
- data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
- data/test/hexapdf/content/test_canvas.rb +1113 -0
- data/test/hexapdf/content/test_color_space.rb +97 -0
- data/test/hexapdf/content/test_graphics_state.rb +138 -0
- data/test/hexapdf/content/test_operator.rb +619 -0
- data/test/hexapdf/content/test_parser.rb +66 -0
- data/test/hexapdf/content/test_processor.rb +156 -0
- data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
- data/test/hexapdf/encryption/common.rb +87 -0
- data/test/hexapdf/encryption/test_aes.rb +121 -0
- data/test/hexapdf/encryption/test_arc4.rb +39 -0
- data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
- data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
- data/test/hexapdf/encryption/test_identity.rb +21 -0
- data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
- data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
- data/test/hexapdf/encryption/test_security_handler.rb +356 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +274 -0
- data/test/hexapdf/filter/common.rb +53 -0
- data/test/hexapdf/filter/test_ascii85_decode.rb +60 -0
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +33 -0
- data/test/hexapdf/filter/test_encryption.rb +24 -0
- data/test/hexapdf/filter/test_flate_decode.rb +35 -0
- data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
- data/test/hexapdf/filter/test_predictor.rb +183 -0
- data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
- data/test/hexapdf/font/cmap/test_parser.rb +67 -0
- data/test/hexapdf/font/cmap/test_writer.rb +58 -0
- data/test/hexapdf/font/encoding/test_base.rb +35 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +21 -0
- data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
- data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
- data/test/hexapdf/font/test_encoding.rb +27 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +110 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +66 -0
- data/test/hexapdf/font/true_type/common.rb +19 -0
- data/test/hexapdf/font/true_type/table/test_cmap.rb +59 -0
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +133 -0
- data/test/hexapdf/font/true_type/table/test_directory.rb +35 -0
- data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
- data/test/hexapdf/font/true_type/table/test_head.rb +76 -0
- data/test/hexapdf/font/true_type/table/test_hhea.rb +40 -0
- data/test/hexapdf/font/true_type/table/test_hmtx.rb +38 -0
- data/test/hexapdf/font/true_type/table/test_loca.rb +43 -0
- data/test/hexapdf/font/true_type/table/test_maxp.rb +62 -0
- data/test/hexapdf/font/true_type/table/test_name.rb +95 -0
- data/test/hexapdf/font/true_type/table/test_os2.rb +65 -0
- data/test/hexapdf/font/true_type/table/test_post.rb +89 -0
- data/test/hexapdf/font/true_type/test_font.rb +120 -0
- data/test/hexapdf/font/true_type/test_table.rb +41 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +51 -0
- data/test/hexapdf/font/type1/test_font.rb +68 -0
- data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +28 -0
- data/test/hexapdf/font_loader/test_standard14.rb +22 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +83 -0
- data/test/hexapdf/image_loader/test_pdf.rb +47 -0
- data/test/hexapdf/image_loader/test_png.rb +258 -0
- data/test/hexapdf/task/test_dereference.rb +46 -0
- data/test/hexapdf/task/test_optimize.rb +137 -0
- data/test/hexapdf/test_configuration.rb +82 -0
- data/test/hexapdf/test_data_dir.rb +32 -0
- data/test/hexapdf/test_dictionary.rb +284 -0
- data/test/hexapdf/test_dictionary_fields.rb +185 -0
- data/test/hexapdf/test_document.rb +574 -0
- data/test/hexapdf/test_document_utils.rb +144 -0
- data/test/hexapdf/test_filter.rb +96 -0
- data/test/hexapdf/test_font_utils.rb +47 -0
- data/test/hexapdf/test_importer.rb +78 -0
- data/test/hexapdf/test_object.rb +177 -0
- data/test/hexapdf/test_parser.rb +394 -0
- data/test/hexapdf/test_rectangle.rb +36 -0
- data/test/hexapdf/test_reference.rb +41 -0
- data/test/hexapdf/test_revision.rb +139 -0
- data/test/hexapdf/test_revisions.rb +93 -0
- data/test/hexapdf/test_serializer.rb +169 -0
- data/test/hexapdf/test_stream.rb +262 -0
- data/test/hexapdf/test_tokenizer.rb +30 -0
- data/test/hexapdf/test_writer.rb +120 -0
- data/test/hexapdf/test_xref_section.rb +35 -0
- data/test/hexapdf/type/test_catalog.rb +30 -0
- data/test/hexapdf/type/test_embedded_file.rb +16 -0
- data/test/hexapdf/type/test_file_specification.rb +148 -0
- data/test/hexapdf/type/test_font.rb +35 -0
- data/test/hexapdf/type/test_font_descriptor.rb +51 -0
- data/test/hexapdf/type/test_font_simple.rb +190 -0
- data/test/hexapdf/type/test_font_type1.rb +128 -0
- data/test/hexapdf/type/test_form.rb +60 -0
- data/test/hexapdf/type/test_info.rb +14 -0
- data/test/hexapdf/type/test_names.rb +9 -0
- data/test/hexapdf/type/test_object_stream.rb +84 -0
- data/test/hexapdf/type/test_page.rb +260 -0
- data/test/hexapdf/type/test_page_tree_node.rb +255 -0
- data/test/hexapdf/type/test_resources.rb +167 -0
- data/test/hexapdf/type/test_trailer.rb +109 -0
- data/test/hexapdf/type/test_xref_stream.rb +131 -0
- data/test/hexapdf/utils/test_bit_field.rb +47 -0
- data/test/hexapdf/utils/test_lru_cache.rb +22 -0
- data/test/hexapdf/utils/test_object_hash.rb +115 -0
- data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +232 -0
- data/test/test_helper.rb +56 -0
- metadata +427 -0
@@ -0,0 +1,204 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
require 'hexapdf/error'
|
35
|
+
require 'hexapdf/stream'
|
36
|
+
require 'hexapdf/xref_section'
|
37
|
+
require 'hexapdf/type/trailer'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module Type
|
41
|
+
|
42
|
+
# Represents PDF type XRef, cross-reference streams.
|
43
|
+
#
|
44
|
+
# A cross-reference stream is used as a more compact representation for an cross-reference
|
45
|
+
# section and trailer dictionary. The trailer dictionary is incorporated into the stream
|
46
|
+
# dictionary and the cross-reference section entries are stored in the stream itself,
|
47
|
+
# compressed to save space.
|
48
|
+
#
|
49
|
+
# == How are Cross-reference Streams Used?
|
50
|
+
#
|
51
|
+
# Cross-reference stream objects are only used when parsing or writing a PDF document.
|
52
|
+
#
|
53
|
+
# When a file is read and a cross-reference stream is found, it is loaded and its information is
|
54
|
+
# stored in a HexaPDF::Revision object. So from a user's perspective nothing changes when a
|
55
|
+
# cross-reference stream instead of a cross-reference section and trailer is encountered.
|
56
|
+
#
|
57
|
+
# This also means that all information stored in a cross-reference stream between parsing and
|
58
|
+
# writing is discarded when the PDF document gets written!
|
59
|
+
#
|
60
|
+
# Upon writing a revision it is checked whether that revision contains a cross-reference
|
61
|
+
# stream object. If it does the cross-reference stream object is updated with the
|
62
|
+
# cross-reference section and trailer information and then written. Otherwise a normal
|
63
|
+
# cross-reference section plus trailer are written.
|
64
|
+
#
|
65
|
+
# See: PDF1.7 s7.5.8
|
66
|
+
class XRefStream < HexaPDF::Stream
|
67
|
+
|
68
|
+
define_field :Type, type: Symbol, default: :XRef, required: true, indirect: false, version: '1.5'
|
69
|
+
# Size is not required because it will be auto-filled before the object is written
|
70
|
+
define_field :Size, type: Integer, indirect: false
|
71
|
+
define_field :Index, type: Array, indirect: false
|
72
|
+
define_field :Prev, type: Integer, indirect: false
|
73
|
+
# W is not required because it will be auto-filled on #update_with_xref_section_and_trailer
|
74
|
+
define_field :W, type: Array, indirect: false
|
75
|
+
|
76
|
+
|
77
|
+
# Returns an XRefSection that represents the content of this cross-reference stream.
|
78
|
+
#
|
79
|
+
# Each invocation returns a new XRefSection object based on the current data in the
|
80
|
+
# associated stream and dictionary.
|
81
|
+
def xref_section
|
82
|
+
index = self[:Index] || [0, self[:Size]]
|
83
|
+
parse_xref_section(index, self[:W])
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns a hash with the entries that represent the file trailer part of the
|
87
|
+
# cross-reference stream's dictionary.
|
88
|
+
#
|
89
|
+
# See: Type::Trailer
|
90
|
+
def trailer
|
91
|
+
Trailer.each_field.with_object({}) do |(name, _data), hash|
|
92
|
+
hash[name] = value[name] if key?(name)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Makes this cross-reference stream represent the data in the given HexaPDF::XRefSection and
|
97
|
+
# Type::Trailer.
|
98
|
+
#
|
99
|
+
# The given cross-reference section is *not* stored but only used to rewrite the associated
|
100
|
+
# stream to reflect the cross-reference section. The dictionary is updated with the
|
101
|
+
# information from the trailer and the needed entries for the cross-reference section.
|
102
|
+
#
|
103
|
+
# If there are changes to the cross-reference section or trailer, this method has to be
|
104
|
+
# invoked again.
|
105
|
+
def update_with_xref_section_and_trailer(xref_section, trailer)
|
106
|
+
value.replace(trailer)
|
107
|
+
value[:Type] = :XRef
|
108
|
+
write_xref_section_to_stream(xref_section)
|
109
|
+
set_filter(:FlateDecode, Columns: value[:W].inject(:+), Predictor: 12)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
TYPE_FREE = 0 #:nodoc:
|
115
|
+
TYPE_IN_USE = 1 #:nodoc:
|
116
|
+
TYPE_COMPRESSED = 2 #:nodoc:
|
117
|
+
|
118
|
+
# Parses the stream and returns the resulting HexaPDF::XRefSection object.
|
119
|
+
def parse_xref_section(index, w)
|
120
|
+
xref = XRefSection.new
|
121
|
+
|
122
|
+
entry_size = w.inject(:+)
|
123
|
+
data = stream
|
124
|
+
pos_in_data = 0
|
125
|
+
|
126
|
+
index.each_slice(2) do |first_oid, number_of_entries|
|
127
|
+
number_of_entries.times do |i|
|
128
|
+
oid = first_oid + i
|
129
|
+
|
130
|
+
# Default for first field: type 1
|
131
|
+
type_field = (w[0] == 0 ? TYPE_IN_USE : bytes_to_int(data, pos_in_data, w[0]))
|
132
|
+
# No default available for second field
|
133
|
+
field2 = bytes_to_int(data, pos_in_data + w[0], w[1])
|
134
|
+
# Default for third field is 0 for type 1, otherwise it needs to be specified!
|
135
|
+
field3 = bytes_to_int(data, pos_in_data + w[0] + w[1], w[2])
|
136
|
+
|
137
|
+
case type_field
|
138
|
+
when TYPE_IN_USE
|
139
|
+
xref.add_in_use_entry(oid, field3, field2)
|
140
|
+
when TYPE_FREE
|
141
|
+
xref.add_free_entry(oid, field3)
|
142
|
+
when TYPE_COMPRESSED
|
143
|
+
xref.add_compressed_entry(oid, field2, field3)
|
144
|
+
else
|
145
|
+
nil # Ignore entry as per PDF1.7 s7.5.8.3
|
146
|
+
end
|
147
|
+
pos_in_data += entry_size
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
xref
|
152
|
+
end
|
153
|
+
|
154
|
+
# Converts +length+ bytes from the +start+ index from the +string+ to an integer.
|
155
|
+
#
|
156
|
+
# The bytes are converted in the big-endian way. If +length+ is zero, zero is returned.
|
157
|
+
def bytes_to_int(string, start, length)
|
158
|
+
result = 0
|
159
|
+
end_index = start + length
|
160
|
+
while start < end_index
|
161
|
+
result = (result << 8) | string.getbyte(start)
|
162
|
+
start += 1
|
163
|
+
end
|
164
|
+
result
|
165
|
+
end
|
166
|
+
|
167
|
+
# Writes the given cross-reference section to the stream and sets the correct /W and /Index
|
168
|
+
# entries for the written data.
|
169
|
+
def write_xref_section_to_stream(xref_section)
|
170
|
+
value[:W], pack_string = calculate_w_entry_and_pack_string(xref_section[oid, gen].pos)
|
171
|
+
value[:Index] = []
|
172
|
+
|
173
|
+
stream = ''.b
|
174
|
+
xref_section.each_subsection do |entries|
|
175
|
+
value[:Index] << entries.first.oid << entries.length
|
176
|
+
entries.each do |entry|
|
177
|
+
data = if entry.in_use?
|
178
|
+
[TYPE_IN_USE, entry.pos, entry.gen]
|
179
|
+
elsif entry.free?
|
180
|
+
[TYPE_FREE, 0, 65535]
|
181
|
+
elsif entry.compressed?
|
182
|
+
[TYPE_COMPRESSED, entry.objstm, entry.pos]
|
183
|
+
else
|
184
|
+
raise HexaPDF::Error, "Unsupported cross-reference entry #{entry}"
|
185
|
+
end
|
186
|
+
stream << data.pack(pack_string)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
self.stream = stream
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the /W entry depending on the given maximal number for the second field as well as
|
193
|
+
# the appropriate entry packing string.
|
194
|
+
def calculate_w_entry_and_pack_string(max_number)
|
195
|
+
middle = Math.log(max_number, 255).ceil
|
196
|
+
middle = 4 if middle == 3
|
197
|
+
pack_string = "C#{'-CnNN'[middle]}n"
|
198
|
+
[[1, middle, 2], pack_string]
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
data/lib/hexapdf/type.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
module HexaPDF
|
35
|
+
|
36
|
+
# == Overview
|
37
|
+
#
|
38
|
+
# The Type module contains implementations of the types defined in the PDF specification.
|
39
|
+
#
|
40
|
+
# Each type class is derived from either the Dictionary class or the Stream class, depending on
|
41
|
+
# whether the type has an associated stream.
|
42
|
+
module Type
|
43
|
+
|
44
|
+
autoload(:XRefStream, 'hexapdf/type/xref_stream')
|
45
|
+
autoload(:ObjectStream, 'hexapdf/type/object_stream')
|
46
|
+
autoload(:Trailer, 'hexapdf/type/trailer')
|
47
|
+
autoload(:Info, 'hexapdf/type/info')
|
48
|
+
autoload(:Catalog, 'hexapdf/type/catalog')
|
49
|
+
autoload(:ViewerPreferences, 'hexapdf/type/viewer_preferences')
|
50
|
+
autoload(:PageTreeNode, 'hexapdf/type/page_tree_node')
|
51
|
+
autoload(:Page, 'hexapdf/type/page')
|
52
|
+
autoload(:Names, 'hexapdf/type/names')
|
53
|
+
autoload(:FileSpecification, 'hexapdf/type/file_specification')
|
54
|
+
autoload(:EmbeddedFile, 'hexapdf/type/embedded_file')
|
55
|
+
autoload(:Resources, 'hexapdf/type/resources')
|
56
|
+
autoload(:GraphicsStateParameter, 'hexapdf/type/graphics_state_parameter')
|
57
|
+
autoload(:Image, 'hexapdf/type/image')
|
58
|
+
autoload(:Form, 'hexapdf/type/form')
|
59
|
+
autoload(:Font, 'hexapdf/type/font')
|
60
|
+
autoload(:FontDescriptor, 'hexapdf/type/font_descriptor')
|
61
|
+
autoload(:FontSimple, 'hexapdf/type/font_simple')
|
62
|
+
autoload(:FontType1, 'hexapdf/type/font_type1')
|
63
|
+
autoload(:FontTrueType, 'hexapdf/type/font_true_type')
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
module HexaPDF
|
35
|
+
module Utils
|
36
|
+
|
37
|
+
# This module is intended to be used to extend class objects. It provides the method #bit_field
|
38
|
+
# for declaring a bit field.
|
39
|
+
module BitField
|
40
|
+
|
41
|
+
# Creates a bit field for managing the integer attribute +name+.
|
42
|
+
#
|
43
|
+
# The +mapping+ argument specifies the mapping of names to bit indices which allows one to use
|
44
|
+
# either the bit name or its index when getting or setting. When using an unknown bit name or
|
45
|
+
# bit index, an error is raised.
|
46
|
+
#
|
47
|
+
# The calling class needs to respond to \#name and \#name= because these methods are used to
|
48
|
+
# get and set the raw integer value.
|
49
|
+
#
|
50
|
+
# After invoking the method the calling class has three new instance methods:
|
51
|
+
#
|
52
|
+
# * NAME_values which returns an array of bit names representing the set bits.
|
53
|
+
# * NAME_include?(bit) which returns true if the given bit is set.
|
54
|
+
# * set_NAME(*bits, clear_existing: false) for setting the given bits.
|
55
|
+
#
|
56
|
+
# The method names can be overridden using the arguments +lister+, +getter+ and +setter+.
|
57
|
+
def bit_field(name, mapping, lister: "#{name}_values", getter: "#{name}_include?",
|
58
|
+
setter: "set_#{name}")
|
59
|
+
bit_names = mapping.keys
|
60
|
+
mapping.default_proc = proc do |h, k|
|
61
|
+
if h.value?(k)
|
62
|
+
h[k] = k
|
63
|
+
else
|
64
|
+
raise ArgumentError, "Invalid bit field name or index '#{k}' for #{self.name}##{name}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
value_getter = name
|
68
|
+
value_setter = "#{name}="
|
69
|
+
|
70
|
+
define_method(lister) do
|
71
|
+
bit_names.map {|n| send(getter, n) ? n : nil}.compact
|
72
|
+
end
|
73
|
+
define_method(getter) do |bit|
|
74
|
+
(send(value_getter) || 0)[mapping[bit]] == 1
|
75
|
+
end
|
76
|
+
define_method(setter) do |*bits, clear_existing: false|
|
77
|
+
send(value_setter, 0) if clear_existing || send(value_getter).nil?
|
78
|
+
result = send(value_getter)
|
79
|
+
bits.each {|bit| result |= 1 << mapping[bit]}
|
80
|
+
send(value_setter, result)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
require 'hexapdf/error'
|
35
|
+
|
36
|
+
module HexaPDF
|
37
|
+
module Utils
|
38
|
+
|
39
|
+
# Helper class for reading variable length integers from a bit stream.
|
40
|
+
#
|
41
|
+
# This class allows one to read integers with a variable width of up to 16 bit from a bit
|
42
|
+
# stream using the #read method. The data from where these bits are read, can be set on
|
43
|
+
# intialization and additional data can later be appended.
|
44
|
+
class BitStreamReader
|
45
|
+
|
46
|
+
# Creates a new object, optionally providing the string from where the bits should be read.
|
47
|
+
def initialize(data = '')
|
48
|
+
@data = data.force_encoding(Encoding::BINARY)
|
49
|
+
@pos = 0
|
50
|
+
@bit_cache = 0
|
51
|
+
@available_bits = 0
|
52
|
+
end
|
53
|
+
|
54
|
+
# Appends some data to the string from where bits are read.
|
55
|
+
def append_data(str)
|
56
|
+
@data = @data[@pos, @data.length - @pos] << str
|
57
|
+
@pos = 0
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the number of remaining bits that can be read.
|
61
|
+
def remaining_bits
|
62
|
+
(@data.length - @pos) * 8 + @available_bits
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns +true+ if +bits+ number of bits can be read.
|
66
|
+
def read?(bits)
|
67
|
+
fill_bit_cache
|
68
|
+
@available_bits >= bits
|
69
|
+
end
|
70
|
+
|
71
|
+
# Reads +bits+ number of bits.
|
72
|
+
#
|
73
|
+
# Raises an exception if not enough bits are available for reading.
|
74
|
+
def read(bits)
|
75
|
+
fill_bit_cache
|
76
|
+
raise HexaPDF::Error, "Not enough bits available for reading" if @available_bits < bits
|
77
|
+
|
78
|
+
@available_bits -= bits
|
79
|
+
result = @bit_cache >> @available_bits
|
80
|
+
@bit_cache &= (1 << @available_bits) - 1
|
81
|
+
|
82
|
+
result
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
LENGTH_TO_TYPE = {4 => 'N', 2 => 'n', 1 => 'C'} # :nodoc:
|
88
|
+
FOUR_TO_INFINITY = 4..Float::INFINITY # :nodoc:
|
89
|
+
|
90
|
+
# Fills the bit cache so that at least 16bit are available (if possible).
|
91
|
+
def fill_bit_cache
|
92
|
+
return unless @available_bits <= 16 && @pos != @data.size
|
93
|
+
|
94
|
+
l = case @data.size - @pos
|
95
|
+
when FOUR_TO_INFINITY then 4
|
96
|
+
when 2, 3 then 2
|
97
|
+
else 1
|
98
|
+
end
|
99
|
+
@bit_cache = (@bit_cache << 8 * l) | @data[@pos, l].unpack(LENGTH_TO_TYPE[l]).first
|
100
|
+
@pos += l
|
101
|
+
@available_bits += 8 * l
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# Helper class for writing out variable length integers one after another as bit stream.
|
107
|
+
#
|
108
|
+
# This class allows one to write integers with a variable width of up to 16 bit to a bit
|
109
|
+
# stream using the #write method. Every time when at least 16 bits are available, the #write
|
110
|
+
# method returns those 16 bits as string and removes them from the internal cache.
|
111
|
+
#
|
112
|
+
# Once all data has been written, the #finalize method must be called to get the last
|
113
|
+
# remaining bits (again as a string).
|
114
|
+
class BitStreamWriter
|
115
|
+
|
116
|
+
def initialize # :nodoc:
|
117
|
+
@bit_cache = 0
|
118
|
+
@available_bits = 0
|
119
|
+
end
|
120
|
+
|
121
|
+
# Writes the integer +int+ with a width of +bits+ to the bit stream.
|
122
|
+
#
|
123
|
+
# Returns a 16bit binary string if enough bits are available or an empty binary string
|
124
|
+
# otherwise.
|
125
|
+
def write(int, bits)
|
126
|
+
@available_bits += bits
|
127
|
+
@bit_cache |= int << (32 - @available_bits)
|
128
|
+
if @available_bits >= 16
|
129
|
+
@available_bits -= 16
|
130
|
+
result = (@bit_cache >> 24).chr << ((@bit_cache >> 16) & 0xFF).chr
|
131
|
+
@bit_cache = (@bit_cache & 0xFFFF) << 16
|
132
|
+
result
|
133
|
+
else
|
134
|
+
''.b
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Retrieves the final (zero padded) bits as a string.
|
139
|
+
def finalize
|
140
|
+
result = [@bit_cache].pack('N')[0...(@available_bits / 8.0).ceil]
|
141
|
+
initialize
|
142
|
+
result
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
module HexaPDF
|
35
|
+
module Utils
|
36
|
+
|
37
|
+
# A simple least recently used (LRU) cache.
|
38
|
+
#
|
39
|
+
# The cache relies on the fact that Ruby's Hash class maintains insertion order. So deleting
|
40
|
+
# and re-inserting a key-value pair on access moves the key to the last position. When an
|
41
|
+
# entry is added and the cache is full, the first entry is removed.
|
42
|
+
class LRUCache
|
43
|
+
|
44
|
+
# Creates a new LRUCache that can hold +size+ entries.
|
45
|
+
def initialize(size)
|
46
|
+
@size = size
|
47
|
+
@cache = {}
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the stored value for +key+ or +nil+ if no value was stored under the key.
|
51
|
+
def [](key)
|
52
|
+
(val = @cache.delete(key)).nil? ? nil : @cache[key] = val
|
53
|
+
end
|
54
|
+
|
55
|
+
# Stores the +value+ under the +key+.
|
56
|
+
def []=(key, value)
|
57
|
+
@cache.delete(key)
|
58
|
+
@cache[key] = value
|
59
|
+
@cache.shift if @cache.length > @size
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2016 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#++
|
33
|
+
|
34
|
+
module HexaPDF
|
35
|
+
module Utils
|
36
|
+
|
37
|
+
# This module provides some mathematical helper functions.
|
38
|
+
module MathHelpers
|
39
|
+
|
40
|
+
module_function
|
41
|
+
|
42
|
+
# Converts degrees to radians.
|
43
|
+
def deg_to_rad(degrees)
|
44
|
+
degrees * Math::PI / 180
|
45
|
+
end
|
46
|
+
|
47
|
+
# Converts radians to degress.
|
48
|
+
def rad_to_deg(radians)
|
49
|
+
radians * 180 / Math::PI
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|