hexapdf 0.17.1 → 0.17.2
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 +1024 -0
- data/LICENSE +29 -0
- data/README.md +129 -0
- data/Rakefile +109 -0
- data/agpl-3.0.txt +661 -0
- data/examples/001-hello_world.rb +16 -0
- data/examples/002-graphics.rb +275 -0
- data/examples/003-arcs.rb +50 -0
- data/examples/004-optimizing.rb +23 -0
- data/examples/005-merging.rb +27 -0
- data/examples/006-standard_pdf_fonts.rb +73 -0
- data/examples/007-truetype.rb +42 -0
- data/examples/008-show_char_bboxes.rb +55 -0
- data/examples/009-text_layouter_alignment.rb +47 -0
- data/examples/010-text_layouter_inline_boxes.rb +64 -0
- data/examples/011-text_layouter_line_wrapping.rb +57 -0
- data/examples/012-text_layouter_styling.rb +122 -0
- data/examples/013-text_layouter_shapes.rb +176 -0
- data/examples/014-text_in_polygon.rb +60 -0
- data/examples/015-boxes.rb +76 -0
- data/examples/016-frame_automatic_box_placement.rb +90 -0
- data/examples/017-frame_text_flow.rb +60 -0
- data/examples/018-composer.rb +44 -0
- data/examples/019-acro_form.rb +88 -0
- data/examples/emoji-smile.png +0 -0
- data/examples/emoji-wink.png +0 -0
- data/examples/machupicchu.jpg +0 -0
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
- data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
- data/lib/hexapdf/version.rb +1 -1
- 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/images/ycck.jpg +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 +236 -0
- data/test/hexapdf/content/common.rb +39 -0
- data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
- data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
- data/test/hexapdf/content/test_canvas.rb +1279 -0
- data/test/hexapdf/content/test_color_space.rb +176 -0
- data/test/hexapdf/content/test_graphics_state.rb +151 -0
- data/test/hexapdf/content/test_operator.rb +619 -0
- data/test/hexapdf/content/test_parser.rb +99 -0
- data/test/hexapdf/content/test_processor.rb +163 -0
- data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
- data/test/hexapdf/document/test_files.rb +72 -0
- data/test/hexapdf/document/test_fonts.rb +60 -0
- data/test/hexapdf/document/test_images.rb +72 -0
- data/test/hexapdf/document/test_pages.rb +130 -0
- data/test/hexapdf/encryption/common.rb +87 -0
- data/test/hexapdf/encryption/test_aes.rb +129 -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 +380 -0
- data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
- data/test/hexapdf/filter/common.rb +53 -0
- data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
- data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
- data/test/hexapdf/filter/test_crypt.rb +21 -0
- data/test/hexapdf/filter/test_encryption.rb +24 -0
- data/test/hexapdf/filter/test_flate_decode.rb +44 -0
- data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
- data/test/hexapdf/filter/test_predictor.rb +219 -0
- data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
- data/test/hexapdf/font/cmap/test_parser.rb +102 -0
- data/test/hexapdf/font/cmap/test_writer.rb +66 -0
- data/test/hexapdf/font/encoding/test_base.rb +45 -0
- data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -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_cmap.rb +104 -0
- data/test/hexapdf/font/test_encoding.rb +27 -0
- data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
- data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
- data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
- data/test/hexapdf/font/true_type/common.rb +17 -0
- data/test/hexapdf/font/true_type/table/common.rb +27 -0
- data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
- data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
- data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
- data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
- data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
- data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
- data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
- data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
- data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
- data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
- data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
- data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
- data/test/hexapdf/font/true_type/test_builder.rb +42 -0
- data/test/hexapdf/font/true_type/test_font.rb +116 -0
- data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
- data/test/hexapdf/font/true_type/test_table.rb +48 -0
- data/test/hexapdf/font/type1/common.rb +6 -0
- data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
- data/test/hexapdf/font/type1/test_font.rb +104 -0
- data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
- data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
- data/test/hexapdf/font_loader/test_from_file.rb +36 -0
- data/test/hexapdf/font_loader/test_standard14.rb +33 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
- data/test/hexapdf/image_loader/test_pdf.rb +47 -0
- data/test/hexapdf/image_loader/test_png.rb +259 -0
- data/test/hexapdf/layout/test_box.rb +154 -0
- data/test/hexapdf/layout/test_frame.rb +350 -0
- data/test/hexapdf/layout/test_image_box.rb +73 -0
- data/test/hexapdf/layout/test_inline_box.rb +71 -0
- data/test/hexapdf/layout/test_line.rb +206 -0
- data/test/hexapdf/layout/test_style.rb +790 -0
- data/test/hexapdf/layout/test_text_box.rb +140 -0
- data/test/hexapdf/layout/test_text_fragment.rb +375 -0
- data/test/hexapdf/layout/test_text_layouter.rb +758 -0
- data/test/hexapdf/layout/test_text_shaper.rb +62 -0
- data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
- data/test/hexapdf/task/test_dereference.rb +51 -0
- data/test/hexapdf/task/test_optimize.rb +162 -0
- data/test/hexapdf/test_composer.rb +258 -0
- data/test/hexapdf/test_configuration.rb +93 -0
- data/test/hexapdf/test_data_dir.rb +32 -0
- data/test/hexapdf/test_dictionary.rb +340 -0
- data/test/hexapdf/test_dictionary_fields.rb +269 -0
- data/test/hexapdf/test_document.rb +641 -0
- data/test/hexapdf/test_filter.rb +100 -0
- data/test/hexapdf/test_importer.rb +106 -0
- data/test/hexapdf/test_object.rb +258 -0
- data/test/hexapdf/test_parser.rb +645 -0
- data/test/hexapdf/test_pdf_array.rb +169 -0
- data/test/hexapdf/test_rectangle.rb +73 -0
- data/test/hexapdf/test_reference.rb +50 -0
- data/test/hexapdf/test_revision.rb +188 -0
- data/test/hexapdf/test_revisions.rb +196 -0
- data/test/hexapdf/test_serializer.rb +195 -0
- data/test/hexapdf/test_stream.rb +274 -0
- data/test/hexapdf/test_tokenizer.rb +80 -0
- data/test/hexapdf/test_type.rb +18 -0
- data/test/hexapdf/test_writer.rb +140 -0
- data/test/hexapdf/test_xref_section.rb +61 -0
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
- data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
- data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
- data/test/hexapdf/type/acro_form/test_field.rb +259 -0
- data/test/hexapdf/type/acro_form/test_form.rb +357 -0
- data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
- data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
- data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
- data/test/hexapdf/type/actions/test_launch.rb +24 -0
- data/test/hexapdf/type/actions/test_uri.rb +23 -0
- data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
- data/test/hexapdf/type/annotations/test_text.rb +34 -0
- data/test/hexapdf/type/annotations/test_widget.rb +225 -0
- data/test/hexapdf/type/test_annotation.rb +97 -0
- data/test/hexapdf/type/test_catalog.rb +48 -0
- data/test/hexapdf/type/test_cid_font.rb +61 -0
- data/test/hexapdf/type/test_file_specification.rb +141 -0
- data/test/hexapdf/type/test_font.rb +67 -0
- data/test/hexapdf/type/test_font_descriptor.rb +61 -0
- data/test/hexapdf/type/test_font_simple.rb +176 -0
- data/test/hexapdf/type/test_font_true_type.rb +31 -0
- data/test/hexapdf/type/test_font_type0.rb +120 -0
- data/test/hexapdf/type/test_font_type1.rb +142 -0
- data/test/hexapdf/type/test_font_type3.rb +26 -0
- data/test/hexapdf/type/test_form.rb +120 -0
- data/test/hexapdf/type/test_image.rb +261 -0
- data/test/hexapdf/type/test_info.rb +9 -0
- data/test/hexapdf/type/test_object_stream.rb +117 -0
- data/test/hexapdf/type/test_page.rb +598 -0
- data/test/hexapdf/type/test_page_tree_node.rb +315 -0
- data/test/hexapdf/type/test_resources.rb +209 -0
- data/test/hexapdf/type/test_trailer.rb +116 -0
- data/test/hexapdf/type/test_xref_stream.rb +143 -0
- data/test/hexapdf/utils/test_bit_field.rb +63 -0
- data/test/hexapdf/utils/test_bit_stream.rb +69 -0
- data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
- data/test/hexapdf/utils/test_lru_cache.rb +22 -0
- data/test/hexapdf/utils/test_object_hash.rb +120 -0
- data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
- data/test/test_helper.rb +58 -0
- metadata +263 -3
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/annotation'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::Annotation::AppearanceDictionary do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@ap = @doc.add({N: :n, D: :d, R: :r}, type: :XXAppearanceDictionary)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "resolves the normal appearance" do
|
|
14
|
+
assert_equal(:n, @ap.normal_appearance)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "resolves the rollover appearance" do
|
|
18
|
+
assert_equal(:r, @ap.rollover_appearance)
|
|
19
|
+
@ap.delete(:R)
|
|
20
|
+
assert_equal(:n, @ap.rollover_appearance)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "resolves the down appearance" do
|
|
24
|
+
assert_equal(:d, @ap.down_appearance)
|
|
25
|
+
@ap.delete(:D)
|
|
26
|
+
assert_equal(:n, @ap.down_appearance)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe HexaPDF::Type::Annotation do
|
|
31
|
+
before do
|
|
32
|
+
@doc = HexaPDF::Document.new
|
|
33
|
+
@annot = @doc.add({Type: :Annot, F: 0b100011})
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "must always be indirect" do
|
|
37
|
+
@annot.must_be_indirect = false
|
|
38
|
+
assert(@annot.must_be_indirect?)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "returns the appearance dictionary" do
|
|
42
|
+
@annot[:AP] = :yes
|
|
43
|
+
assert_equal(:yes, @annot.appearance_dict)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "returns the appearance stream of the given type" do
|
|
47
|
+
assert_nil(@annot.appearance)
|
|
48
|
+
|
|
49
|
+
@annot[:AP] = {N: {}}
|
|
50
|
+
assert_nil(@annot.appearance)
|
|
51
|
+
|
|
52
|
+
stream = @doc.wrap({}, stream: '')
|
|
53
|
+
@annot[:AP][:N] = stream
|
|
54
|
+
assert_nil(@annot.appearance)
|
|
55
|
+
|
|
56
|
+
stream[:BBox] = [1, 2, 3, 4]
|
|
57
|
+
appearance = @annot.appearance
|
|
58
|
+
assert_same(stream.data, appearance.data)
|
|
59
|
+
assert_equal(:Form, appearance[:Subtype])
|
|
60
|
+
|
|
61
|
+
@annot[:AP][:N] = {X: {}}
|
|
62
|
+
assert_nil(@annot.appearance)
|
|
63
|
+
|
|
64
|
+
@annot[:AS] = :X
|
|
65
|
+
@annot[:AP][:N][:X] = stream
|
|
66
|
+
assert_same(stream.data, @annot.appearance.data)
|
|
67
|
+
|
|
68
|
+
@annot[:AP][:D] = {X: stream}
|
|
69
|
+
assert_same(stream.data, @annot.appearance(:down).data)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe "flags" do
|
|
73
|
+
it "returns all flags" do
|
|
74
|
+
assert_equal([:invisible, :hidden, :no_view], @annot.flags)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe "flagged?" do
|
|
79
|
+
it "returns true if the given flag is set" do
|
|
80
|
+
assert(@annot.flagged?(:hidden))
|
|
81
|
+
refute(@annot.flagged?(:locked))
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "raises an error if an unknown flag name is provided" do
|
|
85
|
+
assert_raises(ArgumentError) { @annot.flagged?(:unknown) }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
describe "flag" do
|
|
90
|
+
it "sets the given flag bits" do
|
|
91
|
+
@annot.flag(:locked)
|
|
92
|
+
assert_equal([:invisible, :hidden, :no_view, :locked], @annot.flags)
|
|
93
|
+
@annot.flag(:locked, clear_existing: true)
|
|
94
|
+
assert_equal([:locked], @annot.flags)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/catalog'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::Catalog do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@catalog = @doc.add({Type: :Catalog})
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "must always be indirect" do
|
|
14
|
+
@catalog.must_be_indirect = false
|
|
15
|
+
assert(@catalog.must_be_indirect?)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "creates the page tree on access" do
|
|
19
|
+
assert_nil(@catalog[:Pages])
|
|
20
|
+
pages = @catalog.pages
|
|
21
|
+
assert_equal(:Pages, pages.type)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "acro_form" do
|
|
25
|
+
it "returns an existing form object" do
|
|
26
|
+
@catalog[:AcroForm] = :test
|
|
27
|
+
assert_equal(:test, @catalog.acro_form)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "returns an existing form object even if create: true" do
|
|
31
|
+
@catalog[:AcroForm] = :test
|
|
32
|
+
assert_equal(:test, @catalog.acro_form(create: true))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "creates a new AcroForm object with defaults if create: true" do
|
|
36
|
+
form = @catalog.acro_form(create: true)
|
|
37
|
+
assert_kind_of(HexaPDF::Type::AcroForm::Form, form)
|
|
38
|
+
assert(form[:DA])
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "validation" do
|
|
43
|
+
it "creates the page tree if necessary" do
|
|
44
|
+
refute(@catalog.validate(auto_correct: false))
|
|
45
|
+
assert(@catalog.validate)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/cid_font'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::CIDFont do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@font = @doc.wrap({Type: :Font, Subtype: :CIDFontType2, W: [1, 2, 3], DW: 100,
|
|
11
|
+
CIDSystemInfo: {Registry: 'Adobe', Ordering: 'Japan1', Supplement: 1}})
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "width" do
|
|
15
|
+
before do
|
|
16
|
+
@font[:W] = [1, [1], 2, [2, 3, 4], 5, 6, 10, 20, [20, 21], 30, 32, 40]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "returns the glyph width for a CID defined via the /W array" do
|
|
20
|
+
assert_equal(1, @font.width(1))
|
|
21
|
+
assert_equal(2, @font.width(2))
|
|
22
|
+
assert_equal(3, @font.width(3))
|
|
23
|
+
assert_equal(4, @font.width(4))
|
|
24
|
+
assert_equal(10, @font.width(5))
|
|
25
|
+
assert_equal(10, @font.width(6))
|
|
26
|
+
assert_equal(20, @font.width(20))
|
|
27
|
+
assert_equal(21, @font.width(21))
|
|
28
|
+
assert_equal(40, @font.width(32))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "returns the /DW value for CIDs not in the /W array" do
|
|
32
|
+
assert_equal(100, @font.width(100))
|
|
33
|
+
@font.delete(:DW)
|
|
34
|
+
assert_equal(1000, @font.width(100))
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe "set_widths" do
|
|
39
|
+
it "allows setting the widths" do
|
|
40
|
+
@font.set_widths([[1, 1], [2, 2], [4, 4], [5, 5], [7, 7.1]], default_width: 5.1)
|
|
41
|
+
assert_equal(5, @font[:DW])
|
|
42
|
+
assert_equal([1, [1, 2], 4, [4, 5], 7, [7]], @font[:W].value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "handles an empty widths array correctly" do
|
|
46
|
+
@font.set_widths([], default_width: 100)
|
|
47
|
+
refute(@font.key?(:W))
|
|
48
|
+
assert_equal(100, @font[:DW])
|
|
49
|
+
|
|
50
|
+
@font.set_widths([])
|
|
51
|
+
refute(@font.key?(:W))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "handles setting /DW to the default value correctly" do
|
|
55
|
+
@font.set_widths([])
|
|
56
|
+
refute(@font.key?(:DW))
|
|
57
|
+
@font.set_widths([[1, 1]])
|
|
58
|
+
refute(@font.key?(:DW))
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'stringio'
|
|
6
|
+
require 'hexapdf/type/file_specification'
|
|
7
|
+
require 'hexapdf/document'
|
|
8
|
+
|
|
9
|
+
describe HexaPDF::Type::FileSpecification do
|
|
10
|
+
before do
|
|
11
|
+
@doc = HexaPDF::Document.new
|
|
12
|
+
@obj = HexaPDF::Type::FileSpecification.new({}, document: @doc)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "can be asked whether it is a URL or a file" do
|
|
16
|
+
refute(@obj.url?)
|
|
17
|
+
@obj[:FS] = :URL
|
|
18
|
+
assert(@obj.url?)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe "path" do
|
|
22
|
+
it "returns the first useable file spec string" do
|
|
23
|
+
@obj[:DOS] = 'hälo'.b
|
|
24
|
+
assert_equal('hälo'.b, @obj.path)
|
|
25
|
+
|
|
26
|
+
@obj[:UF] = 'hälo'
|
|
27
|
+
assert_equal('hälo', @obj.path)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "unescapes the path string according to the PDF spec" do
|
|
31
|
+
@obj[:F] = "dir/in\\/out\\too"
|
|
32
|
+
assert_equal('dir/in/out/too', @obj.path)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe "path=" do
|
|
37
|
+
it "only sets /UF and /F, deleting /Mac, /Unix, /DOS entries if they exist" do
|
|
38
|
+
@obj[:Unix] = @obj[:Mac] = @obj[:DOS] = 'a'
|
|
39
|
+
@obj.path = 'file/test'
|
|
40
|
+
assert_equal('file/test', @obj[:UF])
|
|
41
|
+
assert_equal('file/test', @obj[:F])
|
|
42
|
+
refute(@obj.key?(:Unix))
|
|
43
|
+
refute(@obj.key?(:Mac))
|
|
44
|
+
refute(@obj.key?(:DOS))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'resets the /FS value' do
|
|
48
|
+
@obj[:FS] = :Something
|
|
49
|
+
@obj.path = 'file'
|
|
50
|
+
refute(@obj.key?(:FS))
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "url=" do
|
|
55
|
+
it "sets the path and the file system entry" do
|
|
56
|
+
url = 'http://example.com/some?test=ing#done'
|
|
57
|
+
@obj.url = url
|
|
58
|
+
assert_equal(url, @obj.path)
|
|
59
|
+
assert(@obj.url?)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "fails if the provided string is not a valid URL" do
|
|
63
|
+
assert_raises(HexaPDF::Error) { @obj.url = "a false \\ URL" }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "embedded_file?" do
|
|
68
|
+
it "checks whether the specification has an embedded file" do
|
|
69
|
+
refute(@obj.embedded_file?)
|
|
70
|
+
@obj[:EF] = {UF: {}}
|
|
71
|
+
assert(@obj.embedded_file?)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "embedded_file_stream" do
|
|
76
|
+
it "returns the associated embedded file stream" do
|
|
77
|
+
assert_nil(@obj.embedded_file_stream)
|
|
78
|
+
@obj[:EF] = {F: 'data'}
|
|
79
|
+
assert_equal('data', @obj.embedded_file_stream)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
describe "embed/unembed" do
|
|
84
|
+
before do
|
|
85
|
+
@file = Tempfile.new('file-embed-test')
|
|
86
|
+
@file.write("embed-test")
|
|
87
|
+
@file.close
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
after do
|
|
91
|
+
@file.unlink
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "requires the name argument when given an IO object" do
|
|
95
|
+
assert_raises(ArgumentError) { @obj.embed(StringIO.new) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "embeds the given file and registers it with the global name registry" do
|
|
99
|
+
stream = @obj.embed(@file.path)
|
|
100
|
+
assert_equal(stream, @obj[:EF][:UF])
|
|
101
|
+
assert_equal(stream, @obj[:EF][:F])
|
|
102
|
+
assert_equal(File.basename(@file.path), @obj.path)
|
|
103
|
+
assert_equal(@obj, @doc.catalog[:Names][:EmbeddedFiles].find_entry(@obj.path))
|
|
104
|
+
assert_equal(:FlateDecode, stream[:Filter])
|
|
105
|
+
assert_equal('embed-test', stream.stream)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "embeds the given IO object" do
|
|
109
|
+
@file.open
|
|
110
|
+
stream = @obj.embed(@file, name: 'test')
|
|
111
|
+
assert_equal('embed-test', stream.stream)
|
|
112
|
+
|
|
113
|
+
stream = @obj.embed(StringIO.new('test'), name: 'test')
|
|
114
|
+
assert_equal('test', stream.stream)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "allows overriding the name" do
|
|
118
|
+
@obj.embed(@file.path, name: 'test')
|
|
119
|
+
assert_equal('test', @obj.path)
|
|
120
|
+
assert_equal(@obj, @doc.catalog[:Names][:EmbeddedFiles].find_entry('test'))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "doesn't register the embedded file if instructed to do so" do
|
|
124
|
+
@obj.embed(@file.path, name: 'test', register: false)
|
|
125
|
+
assert_nil(@doc.catalog[:Names])
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "replaces the value of an already registered name" do
|
|
129
|
+
(@doc.catalog[:Names] ||= {})[:EmbeddedFiles] = {}
|
|
130
|
+
@doc.catalog[:Names][:EmbeddedFiles].add_entry('test', 'data')
|
|
131
|
+
@obj.embed(@file.path, name: 'test')
|
|
132
|
+
assert_equal(@obj, @doc.catalog[:Names][:EmbeddedFiles].find_entry('test'))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "unembeds an already embedded file before embedding the new one" do
|
|
136
|
+
@obj.embed(@file.path, name: 'test1')
|
|
137
|
+
@obj.embed(@file.path, name: 'test2')
|
|
138
|
+
assert_equal([['test2', @obj]], @doc.catalog[:Names][:EmbeddedFiles].each_entry.to_a)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/font'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::Font do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
cmap = @doc.add({}, stream: <<-EOF)
|
|
11
|
+
2 beginbfchar
|
|
12
|
+
<20> <0041>
|
|
13
|
+
<22> <0042>
|
|
14
|
+
endbfchar
|
|
15
|
+
EOF
|
|
16
|
+
fd = @doc.add({Type: :FontDescriptor, FontBBox: [0, 1, 2, 3]})
|
|
17
|
+
@font = @doc.add({Type: :Font, BaseFont: :TestFont, FontDescriptor: fd, ToUnicode: cmap})
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "allows setting and returning a font wrapper object" do
|
|
21
|
+
@font.font_wrapper = :fake_wrapper
|
|
22
|
+
assert_equal(:fake_wrapper, @font.font_wrapper)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "must always be an indirect" do
|
|
26
|
+
assert(@font.must_be_indirect?)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe "to_utf" do
|
|
30
|
+
it "uses the /ToUnicode CMap if it is available" do
|
|
31
|
+
assert_equal("A", @font.to_utf8(32))
|
|
32
|
+
assert_equal("B", @font.to_utf8(34))
|
|
33
|
+
assert_raises(HexaPDF::Error) { @font.to_utf8(0) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "calls the configured proc if no /ToUnicode CMap is available" do
|
|
37
|
+
@font.delete(:ToUnicode)
|
|
38
|
+
assert_raises(HexaPDF::Error) { @font.to_utf8(32) }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "bounding_box" do
|
|
43
|
+
it "returns the bounding box" do
|
|
44
|
+
assert_equal([0, 1, 2, 3], @font.bounding_box)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "returns nil if no bounding box information can be found" do
|
|
48
|
+
@font[:FontDescriptor].delete(:FontBBox)
|
|
49
|
+
assert_nil(@font.bounding_box)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "embedded" do
|
|
54
|
+
it "returns true if the font is embedded" do
|
|
55
|
+
refute(@font.embedded?)
|
|
56
|
+
@font[:FontDescriptor][:FontFile] = 5
|
|
57
|
+
assert(@font.embedded?)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe "font_file" do
|
|
62
|
+
it "returns the stream object representing the embedded font file" do
|
|
63
|
+
@font[:FontDescriptor][:FontFile] = 5
|
|
64
|
+
assert_equal(5, @font.font_file)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/font_descriptor'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::FontDescriptor do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
@font_desc = @doc.add({Type: :FontDescriptor, FontName: :Test, Flags: 0b1001001,
|
|
11
|
+
ItalicAngle: 10})
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "flags" do
|
|
15
|
+
it "returns all flags" do
|
|
16
|
+
assert_equal([:fixed_pitch, :script, :italic], @font_desc.flags)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "flagged?" do
|
|
21
|
+
it "returns true if the given flag is set" do
|
|
22
|
+
assert(@font_desc.flagged?(:fixed_pitch))
|
|
23
|
+
refute(@font_desc.flagged?(:serif))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "raises an error if an unknown flag name is provided" do
|
|
27
|
+
assert_raises(ArgumentError) { @font_desc.flagged?(:unknown) }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "flag" do
|
|
32
|
+
it "sets the given flag bits" do
|
|
33
|
+
@font_desc.flag(:serif)
|
|
34
|
+
assert_equal([:fixed_pitch, :serif, :script, :italic], @font_desc.flags)
|
|
35
|
+
@font_desc.flag(:symbolic, clear_existing: true)
|
|
36
|
+
assert_equal([:symbolic], @font_desc.flags)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "validation" do
|
|
41
|
+
it "fails if more than one of /FontFile{,2,3} are set" do
|
|
42
|
+
assert(@font_desc.validate {|*args| p args })
|
|
43
|
+
@font_desc[:FontFile] = @font_desc[:FontFile2] = @doc.add({}, stream: 'test')
|
|
44
|
+
refute(@font_desc.validate)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "deletes the /FontWeight value if it doesn't contain a valid value" do
|
|
48
|
+
@font_desc[:FontWeight] = 350
|
|
49
|
+
refute(@font_desc.validate(auto_correct: false))
|
|
50
|
+
assert(@font_desc.validate)
|
|
51
|
+
refute(@font_desc.key?(:FontWeight))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "updates the /Descent value if it is not a negative number" do
|
|
55
|
+
@font_desc[:Descent] = 5
|
|
56
|
+
refute(@font_desc.validate(auto_correct: false))
|
|
57
|
+
assert(@font_desc.validate)
|
|
58
|
+
assert_equal(-5, @font_desc[:Descent])
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/font_simple'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::FontSimple do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
cmap = @doc.add({}, stream: <<-EOF)
|
|
11
|
+
2 beginbfchar
|
|
12
|
+
<20> <0041>
|
|
13
|
+
<22> <0042>
|
|
14
|
+
endbfchar
|
|
15
|
+
EOF
|
|
16
|
+
font_descriptor = @doc.add({Type: :FontDescriptor, FontName: :Embedded, Flags: 0b100,
|
|
17
|
+
FontBBox: [0, 1, 2, 3], ItalicAngle: 0, Ascent: 900,
|
|
18
|
+
Descent: -100, CapHeight: 800, StemV: 20})
|
|
19
|
+
@font = @doc.add({Type: :Font, Encoding: :WinAnsiEncoding,
|
|
20
|
+
BaseFont: :Embedded, FontDescriptor: font_descriptor, ToUnicode: cmap,
|
|
21
|
+
FirstChar: 32, LastChar: 34, Widths: [600, 0, 700]},
|
|
22
|
+
type: HexaPDF::Type::FontSimple)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe "encoding" do
|
|
26
|
+
it "fails if /Encoding is absent because encoding_from_font is not implemented" do
|
|
27
|
+
@font.delete(:Encoding)
|
|
28
|
+
assert_raises(NotImplementedError) { @font.encoding }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "/Encoding is a name" do
|
|
32
|
+
it "returns a predefined encoding if /Encoding specifies one" do
|
|
33
|
+
assert_equal(HexaPDF::Font::Encoding.for_name(:WinAnsiEncoding), @font.encoding)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "fails if /Encoding is an invalid name because encoding_from_font is not implemented" do
|
|
37
|
+
@font[:Encoding] = :SomethingUnknown
|
|
38
|
+
assert_raises(NotImplementedError) { @font.encoding }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "/Encoding is a dictionary" do
|
|
43
|
+
before do
|
|
44
|
+
@font[:Encoding] = {}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "no /BaseEncoding is specified" do
|
|
48
|
+
it "fails if the font is embedded because encoding_from_font is not implemented" do
|
|
49
|
+
@font[:FontDescriptor][:FontFile] = 5
|
|
50
|
+
assert_raises(NotImplementedError) { @font.encoding }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "fails for a symbolic non-embedded font because encoding_from_font is not implemented" do
|
|
54
|
+
@font[:FontDescriptor].flag(:symbolic, clear_existing: true)
|
|
55
|
+
assert_raises(NotImplementedError) { @font.encoding }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "returns the StandardEncoding for a non-symbolic non-embedded font" do
|
|
59
|
+
@font[:FontDescriptor].flag(clear_existing: true)
|
|
60
|
+
assert_equal(HexaPDF::Font::Encoding.for_name(:StandardEncoding), @font.encoding)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "returns the encoding specified by /BaseEncoding" do
|
|
65
|
+
@font[:Encoding] = {BaseEncoding: :WinAnsiEncoding}
|
|
66
|
+
assert_equal(HexaPDF::Font::Encoding.for_name(:WinAnsiEncoding), @font.encoding)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "fails if /BaseEncoding is invalid because encoding_from_font is not implemented" do
|
|
70
|
+
@font[:Encoding] = {BaseEncoding: :SomethingUnknown}
|
|
71
|
+
assert_raises(NotImplementedError) { @font.encoding }
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "returns a difference encoding if /Differences is specified" do
|
|
75
|
+
@font[:FontDescriptor].flag(clear_existing: true)
|
|
76
|
+
@font[:Encoding][:Differences] = [32, :A, :B, 34, :Z]
|
|
77
|
+
refute_equal(HexaPDF::Font::Encoding.for_name(:StandardEncoding), @font.encoding)
|
|
78
|
+
assert_equal(:A, @font.encoding.name(32))
|
|
79
|
+
assert_equal(:B, @font.encoding.name(33))
|
|
80
|
+
assert_equal(:Z, @font.encoding.name(34))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "fails if the /Differences array contains invalid data" do
|
|
84
|
+
@font[:Encoding][:BaseEncoding] = :WinAnsiEncoding
|
|
85
|
+
@font[:Encoding][:Differences] = [:B, 32, :A, :B, 34, :Z]
|
|
86
|
+
assert_raises(HexaPDF::Error) { @font.encoding }
|
|
87
|
+
|
|
88
|
+
@font[:Encoding][:Differences] = [32, "data", :A, :B, 34, :Z]
|
|
89
|
+
assert_raises(HexaPDF::Error) { @font.encoding }
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "fails if /Encoding contains an invalid value" do
|
|
94
|
+
@font[:Encoding] = 5
|
|
95
|
+
assert_raises(HexaPDF::Error) { @font.encoding }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
describe "decode" do
|
|
100
|
+
it "just returns the bytes of the string since this is a simple 1-byte-per-code font" do
|
|
101
|
+
assert_equal([65, 66], @font.decode("AB"))
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "to_utf" do
|
|
106
|
+
it "uses a /ToUnicode CMap if it is available" do
|
|
107
|
+
assert_equal("A", @font.to_utf8(32))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "uses the font's encoding to map the code to an UTF-8 string if the /ToUnicode is missing" do
|
|
111
|
+
@font.delete(:ToUnicode)
|
|
112
|
+
assert_equal(" ", @font.to_utf8(32))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "calls the configured proc if no correct mapping could be found" do
|
|
116
|
+
@font.delete(:ToUnicode)
|
|
117
|
+
assert_raises(HexaPDF::Error) { @font.to_utf8(0) }
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe "writing_mode" do
|
|
122
|
+
it "is always horizontal" do
|
|
123
|
+
assert_equal(:horizontal, @font.writing_mode)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
describe "width" do
|
|
128
|
+
it "returns the glyph width for a valid code point" do
|
|
129
|
+
assert_equal(600, @font.width(32))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "returns the /MissingWidth of a /FontDescriptor if available and the width was not found" do
|
|
133
|
+
assert_equal(0, @font.width(0))
|
|
134
|
+
@font[:FontDescriptor][:MissingWidth] = 99
|
|
135
|
+
assert_equal(99, @font.width(0))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "returns 0 for a missing code point when FontDescriptor is not available" do
|
|
139
|
+
@font.delete(:FontDescriptor)
|
|
140
|
+
assert_equal(0, @font.width(0))
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
describe "symbolic?" do
|
|
145
|
+
it "return true if the font is symbolic" do
|
|
146
|
+
@font[:FontDescriptor].flag(clear_existing: true)
|
|
147
|
+
refute(@font.symbolic?)
|
|
148
|
+
|
|
149
|
+
@font[:FontDescriptor].flag(:symbolic)
|
|
150
|
+
assert(@font.symbolic?)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "returns nil if it cannot be determined whether the font is symbolic" do
|
|
154
|
+
@font.delete(:FontDescriptor)
|
|
155
|
+
assert_nil(@font.symbolic?)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "defines word spacing as always applicable" do
|
|
160
|
+
assert(@font.word_spacing_applicable?)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
describe "validation" do
|
|
164
|
+
before { assert(@font.validate) }
|
|
165
|
+
|
|
166
|
+
it "validates the existence of required keys" do
|
|
167
|
+
@font.delete(:FirstChar)
|
|
168
|
+
refute(@font.validate)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "validates the lengths of the /Widths field" do
|
|
172
|
+
@font[:Widths] = [65]
|
|
173
|
+
refute(@font.validate)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
require 'hexapdf/document'
|
|
5
|
+
require 'hexapdf/type/font_true_type'
|
|
6
|
+
|
|
7
|
+
describe HexaPDF::Type::FontTrueType do
|
|
8
|
+
before do
|
|
9
|
+
@doc = HexaPDF::Document.new
|
|
10
|
+
font_descriptor = @doc.add({Type: :FontDescriptor, FontName: :Something, Flags: 0b100,
|
|
11
|
+
FontBBox: [0, 1, 2, 3], ItalicAngle: 0, Ascent: 900,
|
|
12
|
+
Descent: -100, CapHeight: 800, StemV: 20})
|
|
13
|
+
@font = @doc.add({Type: :Font, Subtype: :TrueType, Encoding: :WinAnsiEncoding,
|
|
14
|
+
FirstChar: 32, LastChar: 34, Widths: [600, 0, 700],
|
|
15
|
+
BaseFont: :Something, FontDescriptor: font_descriptor})
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "validation" do
|
|
19
|
+
it "ignores some missing fields if the font name is one of the standard PDF fonts" do
|
|
20
|
+
@font[:BaseFont] = :'Arial,Bold'
|
|
21
|
+
[:FirstChar, :LastChar, :Widths, :FontDescriptor].each {|field| @font.delete(field) }
|
|
22
|
+
assert(@font.validate)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "requires that the FontDescriptor key is set" do
|
|
26
|
+
assert(@font.validate)
|
|
27
|
+
@font.delete(:FontDescriptor)
|
|
28
|
+
refute(@font.validate)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|