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,191 @@
|
|
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 'fiber'
|
35
|
+
require 'hexapdf/utils/bit_stream'
|
36
|
+
require 'hexapdf/filter/predictor'
|
37
|
+
require 'hexapdf/error'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module Filter
|
41
|
+
|
42
|
+
# Implements the LZW filter.
|
43
|
+
#
|
44
|
+
# Since LZW uses a tightly packed bit stream in which codes are of varying bit lengths and are
|
45
|
+
# not aligned to byte boundaries, this filter is not as fast as the other filters. If speed is
|
46
|
+
# a concern, the FlateDecode filter should be used instead.
|
47
|
+
#
|
48
|
+
# See: HexaPDF::Filter, PDF1.7 s7.4.4
|
49
|
+
module LZWDecode
|
50
|
+
|
51
|
+
CLEAR_TABLE = 256 # :nodoc:
|
52
|
+
EOD = 257 # :nodoc:
|
53
|
+
|
54
|
+
INITIAL_ENCODER_TABLE = {} #:nodoc:
|
55
|
+
0.upto(255) {|i| INITIAL_ENCODER_TABLE[i.chr.freeze] = i}
|
56
|
+
INITIAL_ENCODER_TABLE[CLEAR_TABLE] = CLEAR_TABLE
|
57
|
+
INITIAL_ENCODER_TABLE[EOD] = EOD
|
58
|
+
|
59
|
+
INITIAL_DECODER_TABLE = {} #:nodoc:
|
60
|
+
0.upto(255) {|i| INITIAL_DECODER_TABLE[i] = i.chr}
|
61
|
+
INITIAL_DECODER_TABLE[CLEAR_TABLE] = CLEAR_TABLE
|
62
|
+
INITIAL_DECODER_TABLE[EOD] = EOD
|
63
|
+
|
64
|
+
# See HexaPDF::Filter
|
65
|
+
def self.decoder(source, options = nil)
|
66
|
+
fib = Fiber.new do
|
67
|
+
# initialize decoder state
|
68
|
+
code_length = 9
|
69
|
+
table = INITIAL_DECODER_TABLE.dup
|
70
|
+
|
71
|
+
stream = HexaPDF::Utils::BitStreamReader.new
|
72
|
+
result = ''.b
|
73
|
+
finished = false
|
74
|
+
last_code = CLEAR_TABLE
|
75
|
+
|
76
|
+
while !finished && source.alive? && (data = source.resume)
|
77
|
+
stream.append_data(data)
|
78
|
+
|
79
|
+
while stream.read?(code_length)
|
80
|
+
code = stream.read(code_length)
|
81
|
+
|
82
|
+
# Decoder is one step behind => subtract 1!
|
83
|
+
# We check the table size before entering the next code into it => subtract 1, but
|
84
|
+
# there is one exception: After table entry 4095 is written, the clear table code
|
85
|
+
# also gets written with code length 12,
|
86
|
+
case table.size
|
87
|
+
when 510, 1022, 2046
|
88
|
+
code_length += 1
|
89
|
+
when 4095
|
90
|
+
if code != CLEAR_TABLE
|
91
|
+
raise FilterError, "Maximum of 12bit for codes in LZW stream exceeded"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
if code == EOD
|
96
|
+
finished = true
|
97
|
+
break
|
98
|
+
elsif code == CLEAR_TABLE
|
99
|
+
# reset decoder state
|
100
|
+
code_length = 9
|
101
|
+
table = INITIAL_DECODER_TABLE.dup
|
102
|
+
elsif last_code == CLEAR_TABLE
|
103
|
+
unless table.key?(code)
|
104
|
+
raise FilterError, "Unknown code in LZW encoded stream found"
|
105
|
+
end
|
106
|
+
result << table[code]
|
107
|
+
else
|
108
|
+
unless table.key?(last_code)
|
109
|
+
raise FilterError, "Unknown code in LZW encoded stream found"
|
110
|
+
end
|
111
|
+
last_str = table[last_code]
|
112
|
+
|
113
|
+
str = if table.key?(code)
|
114
|
+
table[code]
|
115
|
+
else
|
116
|
+
last_str + last_str[0]
|
117
|
+
end
|
118
|
+
result << str
|
119
|
+
table[table.size] = last_str + str[0]
|
120
|
+
end
|
121
|
+
|
122
|
+
last_code = code
|
123
|
+
end
|
124
|
+
|
125
|
+
Fiber.yield(result)
|
126
|
+
result = ''.b
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
if options && options[:Predictor]
|
131
|
+
Predictor.decoder(fib, options)
|
132
|
+
else
|
133
|
+
fib
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# See HexaPDF::Filter
|
138
|
+
def self.encoder(source, options = nil)
|
139
|
+
if options && options[:Predictor]
|
140
|
+
source = Predictor.encoder(source, options)
|
141
|
+
end
|
142
|
+
|
143
|
+
Fiber.new do
|
144
|
+
# initialize encoder state
|
145
|
+
code_length = 9
|
146
|
+
table = INITIAL_ENCODER_TABLE.dup
|
147
|
+
|
148
|
+
# initialize the bit stream with the clear-table marker
|
149
|
+
stream = HexaPDF::Utils::BitStreamWriter.new
|
150
|
+
result = stream.write(CLEAR_TABLE, 9)
|
151
|
+
str = ''.b
|
152
|
+
|
153
|
+
while source.alive? && (data = source.resume)
|
154
|
+
data.each_char do |char|
|
155
|
+
newstr = str + char
|
156
|
+
if table.key?(newstr)
|
157
|
+
str = newstr
|
158
|
+
else
|
159
|
+
result << stream.write(table[str], code_length)
|
160
|
+
table[newstr.freeze] = table.size
|
161
|
+
str = char
|
162
|
+
end
|
163
|
+
|
164
|
+
case table.size
|
165
|
+
when 512 then code_length = 10
|
166
|
+
when 1024 then code_length = 11
|
167
|
+
when 2048 then code_length = 12
|
168
|
+
when 4096
|
169
|
+
result << stream.write(CLEAR_TABLE, code_length)
|
170
|
+
# reset encoder state
|
171
|
+
code_length = 9
|
172
|
+
table = INITIAL_ENCODER_TABLE.dup
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
Fiber.yield(result)
|
177
|
+
result = ''.b
|
178
|
+
end
|
179
|
+
|
180
|
+
result = stream.write(table[str], code_length)
|
181
|
+
result << stream.write(EOD, code_length)
|
182
|
+
result << stream.finalize
|
183
|
+
|
184
|
+
result
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,266 @@
|
|
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 'fiber'
|
35
|
+
require 'hexapdf/error'
|
36
|
+
require 'hexapdf/utils/bit_stream'
|
37
|
+
|
38
|
+
module HexaPDF
|
39
|
+
module Filter
|
40
|
+
|
41
|
+
# Implements the predictor for the LZWDecode and FlateDecode filters.
|
42
|
+
#
|
43
|
+
# Although a predictor isn't a full PDF filter, it is implemented as one in HexaPDF terms to
|
44
|
+
# allow easy chaining of the predictor.
|
45
|
+
#
|
46
|
+
# See: PDF1.7 s7.4.4.3, s7.4.4.4, https://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
|
47
|
+
# (p64f), http://www.w3.org/TR/PNG-Filters.html
|
48
|
+
#
|
49
|
+
#-- Implemenation notes:
|
50
|
+
#
|
51
|
+
# The TIFF encoding and decoding methods are the same, except for the innermost loop. The way
|
52
|
+
# it is implemented is probably not the best but it avoids duplicate code.
|
53
|
+
#
|
54
|
+
# The situation is similar with PNG encoding and decoding.
|
55
|
+
#++
|
56
|
+
module Predictor
|
57
|
+
|
58
|
+
PREDICTOR_PNG_NONE = 0 #:nodoc:
|
59
|
+
PREDICTOR_PNG_SUB = 1 #:nodoc:
|
60
|
+
PREDICTOR_PNG_UP = 2 #:nodoc:
|
61
|
+
PREDICTOR_PNG_AVERAGE = 3 #:nodoc:
|
62
|
+
PREDICTOR_PNG_PAETH = 4 #:nodoc:
|
63
|
+
PREDICTOR_PNG_OPTIMUM = 5 #:nodoc:
|
64
|
+
|
65
|
+
# See HexaPDF::Filter
|
66
|
+
def self.decoder(source, options)
|
67
|
+
execute(:decoder, source, options)
|
68
|
+
end
|
69
|
+
|
70
|
+
# See HexaPDF::Filter
|
71
|
+
def self.encoder(source, options)
|
72
|
+
execute(:encoder, source, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.execute(type, source, options) # :nodoc:
|
76
|
+
return source if !options[:Predictor] || options[:Predictor] == 1
|
77
|
+
|
78
|
+
colors = options[:Colors] || 1
|
79
|
+
bits_per_component = options[:BitsPerComponent] || 8
|
80
|
+
columns = options[:Columns] || 1
|
81
|
+
|
82
|
+
if options[:Predictor] == 2
|
83
|
+
tiff_execute(type, source, colors, bits_per_component, columns)
|
84
|
+
elsif options[:Predictor] >= 10
|
85
|
+
png_execute(type, source, options[:Predictor], colors, bits_per_component, columns)
|
86
|
+
else
|
87
|
+
raise HexaPDF::InvalidPDFObjectError, "Predictor key is invalid: #{options[:Predictor]}"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.tiff_execute(type, source, colors, bits_per_component, columns) # :nodoc:
|
92
|
+
Fiber.new do
|
93
|
+
bytes_per_row = (columns * bits_per_component * colors + 7) / 8
|
94
|
+
mask = (1 << bits_per_component) - 1
|
95
|
+
|
96
|
+
data = ''.b
|
97
|
+
writer = HexaPDF::Utils::BitStreamWriter.new
|
98
|
+
pos = 0
|
99
|
+
|
100
|
+
decode_row = lambda do |result, reader|
|
101
|
+
last_components = [0] * colors
|
102
|
+
(columns * colors).times do |i|
|
103
|
+
i %= colors
|
104
|
+
tmp = (reader.read(bits_per_component) + last_components[i]) & mask
|
105
|
+
result << writer.write(tmp, bits_per_component)
|
106
|
+
last_components[i] = tmp
|
107
|
+
end
|
108
|
+
result << writer.finalize
|
109
|
+
end
|
110
|
+
|
111
|
+
encode_row = lambda do |result, reader|
|
112
|
+
last_components = [0] * colors
|
113
|
+
(columns * colors).times do |i|
|
114
|
+
i %= colors
|
115
|
+
tmp = reader.read(bits_per_component)
|
116
|
+
result << writer.write((tmp - last_components[i]) & mask, bits_per_component)
|
117
|
+
last_components[i] = tmp
|
118
|
+
end
|
119
|
+
result << writer.finalize
|
120
|
+
end
|
121
|
+
|
122
|
+
row_action = (type == :decoder ? decode_row : encode_row)
|
123
|
+
|
124
|
+
while source.alive? && (new_data = source.resume)
|
125
|
+
data.slice!(0...pos)
|
126
|
+
data << new_data
|
127
|
+
|
128
|
+
result = ''.b
|
129
|
+
pos = 0
|
130
|
+
|
131
|
+
while pos + bytes_per_row <= data.length
|
132
|
+
reader = HexaPDF::Utils::BitStreamReader.new(data[pos, bytes_per_row])
|
133
|
+
row_action.call(result, reader)
|
134
|
+
pos += bytes_per_row
|
135
|
+
end
|
136
|
+
|
137
|
+
Fiber.yield(result) unless result.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
unless pos == data.length
|
141
|
+
raise FilterError, "Data is missing for TIFF predictor"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.png_execute(type, source, predictor, colors, bits_per_component, columns) # :nodoc:
|
147
|
+
Fiber.new do
|
148
|
+
bytes_per_pixel = (bits_per_component * colors + 7) / 8
|
149
|
+
bytes_per_row = (columns * bits_per_component * colors + 7) / 8
|
150
|
+
bytes_per_row += 1 if type == :decoder
|
151
|
+
|
152
|
+
# Only on encoding: Arbitrarily choose a predictor if we should choose the optimum
|
153
|
+
predictor = predictor == 15 ? PREDICTOR_PNG_PAETH : predictor - 10
|
154
|
+
|
155
|
+
data = ''.b
|
156
|
+
last_line = "\0".b * (bytes_per_row + 1)
|
157
|
+
pos = 0
|
158
|
+
|
159
|
+
decode_row = lambda do |result|
|
160
|
+
line = data[pos, bytes_per_row]
|
161
|
+
|
162
|
+
case line.getbyte(0)
|
163
|
+
when PREDICTOR_PNG_NONE
|
164
|
+
# nothing to do
|
165
|
+
when PREDICTOR_PNG_SUB
|
166
|
+
(bytes_per_pixel + 1).upto(bytes_per_row - 1) do |i|
|
167
|
+
line.setbyte(i, line.getbyte(i) + line.getbyte(i - bytes_per_pixel))
|
168
|
+
end
|
169
|
+
when PREDICTOR_PNG_UP
|
170
|
+
1.upto(bytes_per_row - 1) do |i|
|
171
|
+
line.setbyte(i, line.getbyte(i) + last_line.getbyte(i))
|
172
|
+
end
|
173
|
+
when PREDICTOR_PNG_AVERAGE
|
174
|
+
1.upto(bytes_per_row - 1) do |i|
|
175
|
+
a = i <= bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
176
|
+
line.setbyte(i, line.getbyte(i) + ((a + last_line.getbyte(i)) >> 1))
|
177
|
+
end
|
178
|
+
when PREDICTOR_PNG_PAETH
|
179
|
+
1.upto(bytes_per_row - 1) do |i|
|
180
|
+
a = i <= bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
181
|
+
b = last_line.getbyte(i)
|
182
|
+
c = i <= bytes_per_pixel ? 0 : last_line.getbyte(i - bytes_per_pixel)
|
183
|
+
|
184
|
+
point = a + b - c
|
185
|
+
pa = (point - a).abs
|
186
|
+
pb = (point - b).abs
|
187
|
+
pc = (point - c).abs
|
188
|
+
|
189
|
+
point = ((pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c))
|
190
|
+
|
191
|
+
line.setbyte(i, line.getbyte(i) + point)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
result << line[1..-1]
|
196
|
+
last_line = line
|
197
|
+
end
|
198
|
+
|
199
|
+
encode_row = lambda do |result|
|
200
|
+
line = predictor.chr.force_encoding(Encoding::BINARY) << data[pos, bytes_per_row]
|
201
|
+
next_last_line = line.dup
|
202
|
+
|
203
|
+
case predictor
|
204
|
+
when PREDICTOR_PNG_NONE
|
205
|
+
# nothing to do
|
206
|
+
when PREDICTOR_PNG_SUB
|
207
|
+
bytes_per_row.downto(bytes_per_pixel + 1) do |i|
|
208
|
+
line.setbyte(i, line.getbyte(i) - line.getbyte(i - bytes_per_pixel))
|
209
|
+
end
|
210
|
+
when PREDICTOR_PNG_UP
|
211
|
+
bytes_per_row.downto(1) do |i|
|
212
|
+
line.setbyte(i, line.getbyte(i) - last_line.getbyte(i))
|
213
|
+
end
|
214
|
+
when PREDICTOR_PNG_AVERAGE
|
215
|
+
bytes_per_row.downto(1) do |i|
|
216
|
+
a = i <= bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
217
|
+
line.setbyte(i, line.getbyte(i) - ((a + last_line.getbyte(i)) >> 1))
|
218
|
+
end
|
219
|
+
when PREDICTOR_PNG_PAETH
|
220
|
+
bytes_per_row.downto(1) do |i|
|
221
|
+
a = i <= bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
222
|
+
b = last_line.getbyte(i)
|
223
|
+
c = i <= bytes_per_pixel ? 0 : last_line.getbyte(i - bytes_per_pixel)
|
224
|
+
|
225
|
+
point = a + b - c
|
226
|
+
pa = (point - a).abs
|
227
|
+
pb = (point - b).abs
|
228
|
+
pc = (point - c).abs
|
229
|
+
|
230
|
+
point = ((pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c))
|
231
|
+
|
232
|
+
line.setbyte(i, line.getbyte(i) - point)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
result << line
|
237
|
+
last_line = next_last_line
|
238
|
+
end
|
239
|
+
|
240
|
+
row_action = (type == :decoder ? decode_row : encode_row)
|
241
|
+
|
242
|
+
while source.alive? && (new_data = source.resume)
|
243
|
+
data.slice!(0...pos)
|
244
|
+
data << new_data
|
245
|
+
|
246
|
+
result = ''.b
|
247
|
+
pos = 0
|
248
|
+
|
249
|
+
while pos + bytes_per_row <= data.length
|
250
|
+
row_action.call(result)
|
251
|
+
pos += bytes_per_row
|
252
|
+
end
|
253
|
+
|
254
|
+
Fiber.yield(result) unless result.empty?
|
255
|
+
end
|
256
|
+
|
257
|
+
unless pos == data.length
|
258
|
+
raise FilterError, "Data is missing for PNG predictor"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
end
|
@@ -0,0 +1,108 @@
|
|
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 'fiber'
|
35
|
+
require 'strscan'
|
36
|
+
require 'hexapdf/error'
|
37
|
+
|
38
|
+
module HexaPDF
|
39
|
+
module Filter
|
40
|
+
|
41
|
+
# Implements the run length filter.
|
42
|
+
#
|
43
|
+
# See: HexaPDF::Filter, PDF1.7 s7.4.5
|
44
|
+
module RunLengthDecode
|
45
|
+
|
46
|
+
EOD = 128.chr #:nodoc:
|
47
|
+
|
48
|
+
# See HexaPDF::Filter
|
49
|
+
def self.decoder(source, _ = nil)
|
50
|
+
Fiber.new do
|
51
|
+
i = 0
|
52
|
+
result = ''.b
|
53
|
+
data = source.resume
|
54
|
+
while data && i < data.length
|
55
|
+
length = data.getbyte(i)
|
56
|
+
if length < 128 && i + length + 1 < data.length # no byte run and enough bytes
|
57
|
+
result << data[i + 1, length + 1]
|
58
|
+
i += length + 2
|
59
|
+
elsif length > 128 && i + 1 < data.length # byte run and enough bytes
|
60
|
+
result << data[i + 1] * (257 - length)
|
61
|
+
i += 2
|
62
|
+
elsif length != 128 # not enough bytes in data
|
63
|
+
Fiber.yield(result)
|
64
|
+
if source.alive? && (new_data = source.resume)
|
65
|
+
data = data[i..-1] << new_data
|
66
|
+
else
|
67
|
+
raise FilterError, "Missing data for run length encoded stream"
|
68
|
+
end
|
69
|
+
i = 0
|
70
|
+
result = ''.b
|
71
|
+
else # EOD reached
|
72
|
+
break
|
73
|
+
end
|
74
|
+
|
75
|
+
if i == data.length && source.alive? && (data = source.resume)
|
76
|
+
Fiber.yield(result)
|
77
|
+
i = 0
|
78
|
+
result = ''.b
|
79
|
+
end
|
80
|
+
end
|
81
|
+
result unless result.empty?
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# See HexaPDF::Filter
|
86
|
+
def self.encoder(source, _ = nil)
|
87
|
+
Fiber.new do
|
88
|
+
while source.alive? && (data = source.resume)
|
89
|
+
result = ''.b
|
90
|
+
strscan = StringScanner.new(data)
|
91
|
+
until strscan.eos?
|
92
|
+
if strscan.scan(/(.)\1{1,127}/m) # a run of <= 128 same characters
|
93
|
+
result << (257 - strscan.matched_size).chr << strscan[1]
|
94
|
+
else # a run of characters until two same characters or length > 128
|
95
|
+
match = strscan.scan(/.{1,128}?(?=(.)\1|\z)|.{128}/m)
|
96
|
+
result << (match.length - 1).chr << match
|
97
|
+
end
|
98
|
+
end
|
99
|
+
Fiber.yield(result)
|
100
|
+
end
|
101
|
+
EOD
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|