hexapdf 0.17.1 → 0.17.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/LICENSE +29 -0
  4. data/README.md +129 -0
  5. data/Rakefile +109 -0
  6. data/agpl-3.0.txt +661 -0
  7. data/examples/001-hello_world.rb +16 -0
  8. data/examples/002-graphics.rb +275 -0
  9. data/examples/003-arcs.rb +50 -0
  10. data/examples/004-optimizing.rb +23 -0
  11. data/examples/005-merging.rb +27 -0
  12. data/examples/006-standard_pdf_fonts.rb +73 -0
  13. data/examples/007-truetype.rb +42 -0
  14. data/examples/008-show_char_bboxes.rb +55 -0
  15. data/examples/009-text_layouter_alignment.rb +47 -0
  16. data/examples/010-text_layouter_inline_boxes.rb +64 -0
  17. data/examples/011-text_layouter_line_wrapping.rb +57 -0
  18. data/examples/012-text_layouter_styling.rb +122 -0
  19. data/examples/013-text_layouter_shapes.rb +176 -0
  20. data/examples/014-text_in_polygon.rb +60 -0
  21. data/examples/015-boxes.rb +76 -0
  22. data/examples/016-frame_automatic_box_placement.rb +90 -0
  23. data/examples/017-frame_text_flow.rb +60 -0
  24. data/examples/018-composer.rb +44 -0
  25. data/examples/019-acro_form.rb +88 -0
  26. data/examples/emoji-smile.png +0 -0
  27. data/examples/emoji-wink.png +0 -0
  28. data/examples/machupicchu.jpg +0 -0
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
  31. data/lib/hexapdf/version.rb +1 -1
  32. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  33. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  34. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  35. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  36. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  37. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  38. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  39. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  40. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  41. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  42. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  43. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  44. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  45. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  46. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  47. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  48. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  49. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  50. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  51. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  52. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  53. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  54. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  55. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  56. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  57. data/test/data/images/cmyk.jpg +0 -0
  58. data/test/data/images/fillbytes.jpg +0 -0
  59. data/test/data/images/gray.jpg +0 -0
  60. data/test/data/images/greyscale-1bit.png +0 -0
  61. data/test/data/images/greyscale-2bit.png +0 -0
  62. data/test/data/images/greyscale-4bit.png +0 -0
  63. data/test/data/images/greyscale-8bit.png +0 -0
  64. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  65. data/test/data/images/greyscale-trns-8bit.png +0 -0
  66. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  67. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  68. data/test/data/images/indexed-1bit.png +0 -0
  69. data/test/data/images/indexed-2bit.png +0 -0
  70. data/test/data/images/indexed-4bit.png +0 -0
  71. data/test/data/images/indexed-8bit.png +0 -0
  72. data/test/data/images/indexed-alpha-4bit.png +0 -0
  73. data/test/data/images/indexed-alpha-8bit.png +0 -0
  74. data/test/data/images/rgb.jpg +0 -0
  75. data/test/data/images/truecolour-8bit.png +0 -0
  76. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  77. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  78. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  79. data/test/data/images/ycck.jpg +0 -0
  80. data/test/data/minimal.pdf +44 -0
  81. data/test/data/standard-security-handler/README +9 -0
  82. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  83. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  84. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  85. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  86. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  87. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  88. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  89. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  90. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  91. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  92. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  93. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  94. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  95. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  96. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  97. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  98. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  99. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  100. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  101. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  102. data/test/hexapdf/common_tokenizer_tests.rb +236 -0
  103. data/test/hexapdf/content/common.rb +39 -0
  104. data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
  105. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
  106. data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
  107. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  108. data/test/hexapdf/content/test_canvas.rb +1279 -0
  109. data/test/hexapdf/content/test_color_space.rb +176 -0
  110. data/test/hexapdf/content/test_graphics_state.rb +151 -0
  111. data/test/hexapdf/content/test_operator.rb +619 -0
  112. data/test/hexapdf/content/test_parser.rb +99 -0
  113. data/test/hexapdf/content/test_processor.rb +163 -0
  114. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  115. data/test/hexapdf/document/test_files.rb +72 -0
  116. data/test/hexapdf/document/test_fonts.rb +60 -0
  117. data/test/hexapdf/document/test_images.rb +72 -0
  118. data/test/hexapdf/document/test_pages.rb +130 -0
  119. data/test/hexapdf/encryption/common.rb +87 -0
  120. data/test/hexapdf/encryption/test_aes.rb +129 -0
  121. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  122. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  123. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  124. data/test/hexapdf/encryption/test_identity.rb +21 -0
  125. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  126. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  127. data/test/hexapdf/encryption/test_security_handler.rb +380 -0
  128. data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
  129. data/test/hexapdf/filter/common.rb +53 -0
  130. data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
  131. data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
  132. data/test/hexapdf/filter/test_crypt.rb +21 -0
  133. data/test/hexapdf/filter/test_encryption.rb +24 -0
  134. data/test/hexapdf/filter/test_flate_decode.rb +44 -0
  135. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  136. data/test/hexapdf/filter/test_predictor.rb +219 -0
  137. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  138. data/test/hexapdf/font/cmap/test_parser.rb +102 -0
  139. data/test/hexapdf/font/cmap/test_writer.rb +66 -0
  140. data/test/hexapdf/font/encoding/test_base.rb +45 -0
  141. data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
  142. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  143. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  144. data/test/hexapdf/font/test_cmap.rb +104 -0
  145. data/test/hexapdf/font/test_encoding.rb +27 -0
  146. data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
  147. data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
  148. data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
  149. data/test/hexapdf/font/true_type/common.rb +17 -0
  150. data/test/hexapdf/font/true_type/table/common.rb +27 -0
  151. data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
  152. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
  153. data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
  154. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  155. data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
  156. data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
  157. data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
  158. data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
  159. data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
  160. data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
  161. data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
  162. data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
  163. data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
  164. data/test/hexapdf/font/true_type/test_builder.rb +42 -0
  165. data/test/hexapdf/font/true_type/test_font.rb +116 -0
  166. data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
  167. data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
  168. data/test/hexapdf/font/true_type/test_table.rb +48 -0
  169. data/test/hexapdf/font/type1/common.rb +6 -0
  170. data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
  171. data/test/hexapdf/font/type1/test_font.rb +104 -0
  172. data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
  173. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  174. data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
  175. data/test/hexapdf/font_loader/test_from_file.rb +36 -0
  176. data/test/hexapdf/font_loader/test_standard14.rb +33 -0
  177. data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
  178. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  179. data/test/hexapdf/image_loader/test_png.rb +259 -0
  180. data/test/hexapdf/layout/test_box.rb +154 -0
  181. data/test/hexapdf/layout/test_frame.rb +350 -0
  182. data/test/hexapdf/layout/test_image_box.rb +73 -0
  183. data/test/hexapdf/layout/test_inline_box.rb +71 -0
  184. data/test/hexapdf/layout/test_line.rb +206 -0
  185. data/test/hexapdf/layout/test_style.rb +790 -0
  186. data/test/hexapdf/layout/test_text_box.rb +140 -0
  187. data/test/hexapdf/layout/test_text_fragment.rb +375 -0
  188. data/test/hexapdf/layout/test_text_layouter.rb +758 -0
  189. data/test/hexapdf/layout/test_text_shaper.rb +62 -0
  190. data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
  191. data/test/hexapdf/task/test_dereference.rb +51 -0
  192. data/test/hexapdf/task/test_optimize.rb +162 -0
  193. data/test/hexapdf/test_composer.rb +258 -0
  194. data/test/hexapdf/test_configuration.rb +93 -0
  195. data/test/hexapdf/test_data_dir.rb +32 -0
  196. data/test/hexapdf/test_dictionary.rb +340 -0
  197. data/test/hexapdf/test_dictionary_fields.rb +269 -0
  198. data/test/hexapdf/test_document.rb +641 -0
  199. data/test/hexapdf/test_filter.rb +100 -0
  200. data/test/hexapdf/test_importer.rb +106 -0
  201. data/test/hexapdf/test_object.rb +258 -0
  202. data/test/hexapdf/test_parser.rb +645 -0
  203. data/test/hexapdf/test_pdf_array.rb +169 -0
  204. data/test/hexapdf/test_rectangle.rb +73 -0
  205. data/test/hexapdf/test_reference.rb +50 -0
  206. data/test/hexapdf/test_revision.rb +188 -0
  207. data/test/hexapdf/test_revisions.rb +196 -0
  208. data/test/hexapdf/test_serializer.rb +195 -0
  209. data/test/hexapdf/test_stream.rb +274 -0
  210. data/test/hexapdf/test_tokenizer.rb +80 -0
  211. data/test/hexapdf/test_type.rb +18 -0
  212. data/test/hexapdf/test_writer.rb +140 -0
  213. data/test/hexapdf/test_xref_section.rb +61 -0
  214. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
  215. data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
  216. data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
  217. data/test/hexapdf/type/acro_form/test_field.rb +259 -0
  218. data/test/hexapdf/type/acro_form/test_form.rb +357 -0
  219. data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
  220. data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
  221. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
  222. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  223. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  224. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  225. data/test/hexapdf/type/annotations/test_text.rb +34 -0
  226. data/test/hexapdf/type/annotations/test_widget.rb +225 -0
  227. data/test/hexapdf/type/test_annotation.rb +97 -0
  228. data/test/hexapdf/type/test_catalog.rb +48 -0
  229. data/test/hexapdf/type/test_cid_font.rb +61 -0
  230. data/test/hexapdf/type/test_file_specification.rb +141 -0
  231. data/test/hexapdf/type/test_font.rb +67 -0
  232. data/test/hexapdf/type/test_font_descriptor.rb +61 -0
  233. data/test/hexapdf/type/test_font_simple.rb +176 -0
  234. data/test/hexapdf/type/test_font_true_type.rb +31 -0
  235. data/test/hexapdf/type/test_font_type0.rb +120 -0
  236. data/test/hexapdf/type/test_font_type1.rb +142 -0
  237. data/test/hexapdf/type/test_font_type3.rb +26 -0
  238. data/test/hexapdf/type/test_form.rb +120 -0
  239. data/test/hexapdf/type/test_image.rb +261 -0
  240. data/test/hexapdf/type/test_info.rb +9 -0
  241. data/test/hexapdf/type/test_object_stream.rb +117 -0
  242. data/test/hexapdf/type/test_page.rb +598 -0
  243. data/test/hexapdf/type/test_page_tree_node.rb +315 -0
  244. data/test/hexapdf/type/test_resources.rb +209 -0
  245. data/test/hexapdf/type/test_trailer.rb +116 -0
  246. data/test/hexapdf/type/test_xref_stream.rb +143 -0
  247. data/test/hexapdf/utils/test_bit_field.rb +63 -0
  248. data/test/hexapdf/utils/test_bit_stream.rb +69 -0
  249. data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
  250. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  251. data/test/hexapdf/utils/test_object_hash.rb +120 -0
  252. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  253. data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
  254. data/test/test_helper.rb +58 -0
  255. metadata +263 -3
@@ -0,0 +1,163 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/content/processor'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::Content::Processor::GlyphBox do
8
+ before do
9
+ @box = HexaPDF::Content::Processor::GlyphBox.new(5, "5", 1, 2, 3, 4, 5, 6)
10
+ end
11
+
12
+ it "returns the correct bounding box coordinates" do
13
+ assert_equal([1, 2], @box.lower_left)
14
+ assert_equal([3, 4], @box.lower_right)
15
+ assert_equal([5, 6], @box.upper_left)
16
+ assert_equal([7, 8], @box.upper_right)
17
+ end
18
+
19
+ it "returns all box corners in one array when using #points" do
20
+ assert_equal([1, 2, 3, 4, 7, 8, 5, 6], @box.points)
21
+ end
22
+ end
23
+
24
+ describe HexaPDF::Content::Processor::CompositeBox do
25
+ before do
26
+ @glyph_box1 = HexaPDF::Content::Processor::GlyphBox.new(4, "4", 1, 1, 2, 1, 1, 2)
27
+ @glyph_box2 = HexaPDF::Content::Processor::GlyphBox.new(2, "2", 3, 1, 7, 1, 3, 2)
28
+ @boxes = HexaPDF::Content::Processor::CompositeBox.new
29
+ end
30
+
31
+ it "allows appending and retrieving of glyph boxes" do
32
+ result = (@boxes << @glyph_box1)
33
+ assert_equal(@boxes, result)
34
+ assert_equal(@glyph_box1, @boxes[0])
35
+ end
36
+
37
+ it "allows iterating over the glyph boxes " do
38
+ @boxes << @glyph_box1 << @glyph_box2
39
+ assert_equal([@glyph_box1, @glyph_box2], @boxes.each.to_a)
40
+ end
41
+
42
+ it "returns the concatenated string of the individual boxes" do
43
+ @boxes << @glyph_box1 << @glyph_box2
44
+ assert_equal("42", @boxes.string)
45
+ end
46
+
47
+ it "returns the correct bounding box coordinates" do
48
+ @boxes << @glyph_box1 << @glyph_box2
49
+ assert_equal([1, 1], @boxes.lower_left)
50
+ assert_equal([7, 1], @boxes.lower_right)
51
+ assert_equal([1, 2], @boxes.upper_left)
52
+ assert_equal([7, 2], @boxes.upper_right)
53
+ end
54
+ end
55
+
56
+ describe HexaPDF::Content::Processor do
57
+ before do
58
+ @processor = HexaPDF::Content::Processor.new
59
+ end
60
+
61
+ describe "initialization" do
62
+ it "has a prepopulated operators mapping" do
63
+ assert_kind_of(HexaPDF::Content::Operator::BaseOperator, @processor.operators[:q])
64
+ end
65
+ end
66
+
67
+ describe "graphics_object" do
68
+ it "default to :none on initialization" do
69
+ assert_equal(:none, @processor.graphics_object)
70
+ end
71
+ end
72
+
73
+ describe "process" do
74
+ it "invokes the specified operator implementation" do
75
+ op = Minitest::Mock.new
76
+ op.expect(:invoke, nil, [@processor, :arg])
77
+ @processor.operators[:test] = op
78
+ @processor.process(:test, [:arg])
79
+ assert(op.verify)
80
+ end
81
+
82
+ it "invokes the mapped message name" do
83
+ val = nil
84
+ @processor.define_singleton_method(:save_graphics_state) { val = :arg }
85
+ @processor.process(:q)
86
+ assert_equal(:arg, val)
87
+ end
88
+ end
89
+
90
+ describe "paint_xobject" do
91
+ it "processes the contents of a Form xobject" do
92
+ test_case = self
93
+ invoked = false
94
+
95
+ @processor.define_singleton_method(:set_line_width) do |_width|
96
+ test_case.assert_equal([2, 0, 0, 2, 10, 10], graphics_state.ctm.to_a)
97
+ invoked = true
98
+ end
99
+ @processor.resources = resources = Object.new
100
+ @processor.resources.define_singleton_method(:xobject) do |_name|
101
+ obj = {Matrix: [2, 0, 0, 2, 10, 10], Subtype: :Form}
102
+ obj.define_singleton_method(:process_contents) do |processor, original_resources:|
103
+ test_case.assert_same(resources, original_resources)
104
+ processor.process(:w, [10])
105
+ end
106
+ obj
107
+ end
108
+
109
+ @processor.process(:Do, [:Name])
110
+ assert(invoked)
111
+ assert_equal([1, 0, 0, 1, 0, 0], @processor.graphics_state.ctm.to_a)
112
+ assert_same(resources, @processor.resources)
113
+ end
114
+ end
115
+
116
+ describe "text decoding" do
117
+ before do
118
+ @doc = HexaPDF::Document.new
119
+ @processor.process(:BT)
120
+ @processor.graphics_state.font = @font = @doc.add({Type: :Font, Subtype: :Type1,
121
+ Encoding: :WinAnsiEncoding,
122
+ BaseFont: :"Times-Roman"})
123
+ @processor.graphics_state.font_size = 10
124
+ @processor.graphics_state.text_rise = 10
125
+ @processor.graphics_state.character_spacing = 1
126
+ @processor.graphics_state.word_spacing = 2
127
+ end
128
+
129
+ describe "decode_text" do
130
+ it "decodes text provided via one or the other of the two show show text operators" do
131
+ assert_equal("Hülle", @processor.send(:decode_text, "Hülle".encode("Windows-1252")))
132
+ arr = ["Hül".encode("Windows-1252"), 20, "le".encode("Windows-1252")]
133
+ assert_equal("Hülle", @processor.send(:decode_text, arr))
134
+ end
135
+ end
136
+
137
+ describe "decode_text_with_positioning" do
138
+ it "returns a composite box with positioning information" do
139
+ lly = @font.bounding_box[1] / 1000.0 * @processor.graphics_state.font_size +
140
+ @processor.graphics_state.text_rise
141
+ lry = @font.bounding_box[3] / 1000.0 * @processor.graphics_state.font_size +
142
+ @processor.graphics_state.text_rise
143
+ arr = ["Hül".encode("Windows-1252"), 20, " le".encode("Windows-1252")]
144
+ width = "Hül le".encode("Windows-1252").codepoints.inject(0) {|s, cp| s + @font.width(cp) }
145
+ width = (width - 20) * @processor.graphics_state.scaled_font_size +
146
+ 6 * @processor.graphics_state.scaled_character_spacing +
147
+ @processor.graphics_state.scaled_word_spacing
148
+
149
+ box = @processor.send(:decode_text_with_positioning, arr)
150
+ assert_equal("Hül le", box.string)
151
+ assert_in_delta(0, box[0].lower_left[0])
152
+ assert_in_delta(lly, box[0].lower_left[1])
153
+ assert_in_delta(width, box[5].upper_right[0])
154
+ assert_in_delta(lry, box[5].upper_right[1])
155
+ end
156
+
157
+ it "fails if the current font is a vertical font" do
158
+ @processor.graphics_state.font.define_singleton_method(:writing_mode) { :vertical }
159
+ assert_raises(NotImplementedError) { @processor.send(:decode_text_with_positioning, "a") }
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,64 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/content/transformation_matrix'
5
+
6
+ describe HexaPDF::Content::TransformationMatrix do
7
+ before do
8
+ @matrix = HexaPDF::Content::TransformationMatrix.new
9
+ end
10
+
11
+ describe "initialize" do
12
+ it "initializes to the identity matrix" do
13
+ assert_equal(1, @matrix.a)
14
+ assert_equal(0, @matrix.b)
15
+ assert_equal(0, @matrix.c)
16
+ assert_equal(1, @matrix.d)
17
+ assert_equal(0, @matrix.e)
18
+ assert_equal(0, @matrix.f)
19
+ end
20
+
21
+ it "can use arbitrary values" do
22
+ @matrix = HexaPDF::Content::TransformationMatrix.new(2, 3, 4, 5, 6, 7)
23
+ assert_equal(2, @matrix.a)
24
+ assert_equal(3, @matrix.b)
25
+ assert_equal(4, @matrix.c)
26
+ assert_equal(5, @matrix.d)
27
+ assert_equal(6, @matrix.e)
28
+ assert_equal(7, @matrix.f)
29
+ end
30
+ end
31
+
32
+ it "correctly evaluates a point" do
33
+ assert_equal([2, 3], @matrix.evaluate(2, 3))
34
+ end
35
+
36
+ it "correctly translates the matrix" do
37
+ @matrix.translate(5, 10)
38
+ assert_equal([7, 13], @matrix.evaluate(2, 3))
39
+ end
40
+
41
+ it "correctly rotates the matrix" do
42
+ @matrix.rotate(90)
43
+ assert_equal([-3, 2], @matrix.evaluate(2, 3))
44
+ end
45
+
46
+ it "correctly scales the matrix" do
47
+ @matrix.scale(5, 10)
48
+ assert_equal([10, 30], @matrix.evaluate(2, 3))
49
+ end
50
+
51
+ it "correctly skews the matrix" do
52
+ assert_equal([2, 5], @matrix.dup.skew(45, 0).evaluate(2, 3))
53
+ assert_equal([5, 3], @matrix.dup.skew(0, 45).evaluate(2, 3))
54
+ end
55
+
56
+ it "can be compared to another matrix" do
57
+ assert_equal(HexaPDF::Content::TransformationMatrix.new, @matrix)
58
+ refute_equal(HexaPDF::Content::TransformationMatrix.new(5), @matrix)
59
+ end
60
+
61
+ it "allows the conversion of the matrix into an array" do
62
+ assert_equal([1, 0, 0, 1, 0, 0], @matrix.to_a)
63
+ end
64
+ end
@@ -0,0 +1,72 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'stringio'
5
+ require 'tempfile'
6
+ require 'hexapdf/document'
7
+
8
+ describe HexaPDF::Document::Files do
9
+ before do
10
+ @doc = HexaPDF::Document.new
11
+ @data = "embed-test"
12
+ @file = Tempfile.new('file-embed-test')
13
+ @file.write(@data)
14
+ @file.close
15
+ end
16
+
17
+ after do
18
+ @file.unlink
19
+ end
20
+
21
+ describe "add" do
22
+ it "adds a file using a filename and embeds it" do
23
+ spec = @doc.files.add(@file.path)
24
+ assert_equal(File.basename(@file.path), spec.path)
25
+ assert_equal(@data, spec.embedded_file_stream.stream)
26
+ end
27
+
28
+ it "adds a reference to a file" do
29
+ spec = @doc.files.add(@file.path, embed: false)
30
+ assert_equal(File.basename(@file.path), spec.path)
31
+ refute(spec.embedded_file?)
32
+ end
33
+
34
+ it "adds a file using an IO" do
35
+ @file.open
36
+ spec = @doc.files.add(@file, name: 'test', embed: false)
37
+ assert_equal('test', spec.path)
38
+ assert_equal(@data, spec.embedded_file_stream.stream)
39
+ end
40
+
41
+ it "optionally sets the description of the file" do
42
+ spec = @doc.files.add(@file.path, description: 'Some file')
43
+ assert_equal('Some file', spec[:Desc])
44
+ end
45
+
46
+ it "requires the name argument when given an IO object" do
47
+ assert_raises(ArgumentError) { @doc.files.add(StringIO.new) }
48
+ end
49
+ end
50
+
51
+ describe "each" do
52
+ it "iterates only over named embedded files and file annotations if search=false" do
53
+ @doc.add({Type: :Filespec})
54
+ spec1 = @doc.files.add(__FILE__)
55
+ spec2 = @doc.add({Type: :Filespec})
56
+ @doc.pages.add # page without annot
57
+ @doc.pages.add[:Annots] = [
58
+ {Subtype: :FileAttachment, FS: HexaPDF::Reference.new(spec1.oid, spec1.gen)},
59
+ {Subtype: :FileAttachment, FS: spec2},
60
+ {},
61
+ ]
62
+ assert_equal([spec1, spec2], @doc.files.to_a)
63
+ end
64
+
65
+ it "iterates over all file specifications of the document if search=true" do
66
+ specs = []
67
+ specs << @doc.add({Type: :Filespec})
68
+ specs << @doc.add({Type: :Filespec})
69
+ assert_equal(specs, @doc.files.each(search: true).to_a)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,60 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+
6
+ describe HexaPDF::Document::Fonts do
7
+ before do
8
+ @doc = HexaPDF::Document.new
9
+ @doc.config['font_loader'] = []
10
+ end
11
+
12
+ describe "add" do
13
+ before do
14
+ @doc.config['font_loader'] << lambda do |doc, name, **options|
15
+ assert_equal(@doc, doc)
16
+ if name == :TestFont
17
+ x = Object.new
18
+ x.define_singleton_method(:name) do
19
+ options[:variant] == :bold ? :BoldFont : :NormalFont
20
+ end
21
+ x
22
+ else
23
+ nil
24
+ end
25
+ end
26
+ end
27
+
28
+ it "loads the specified font" do
29
+ assert_equal(:NormalFont, @doc.fonts.add(:TestFont).name)
30
+ assert_equal(:BoldFont, @doc.fonts.add(:TestFont, variant: :bold).name)
31
+ end
32
+
33
+ it "caches loaded fonts" do
34
+ font = @doc.fonts.add(:TestFont)
35
+ assert_same(font, @doc.fonts.add(:TestFont))
36
+ assert_same(font, @doc.fonts.add(:TestFont, variant: :none))
37
+ end
38
+
39
+ it "fails if the requested font is not found" do
40
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::Standard14'
41
+ error = assert_raises(HexaPDF::Error) { @doc.fonts.add("Unknown") }
42
+ assert_match(/Times \(none/, error.message)
43
+ end
44
+
45
+ it "raises an error if a font loader cannot be correctly retrieved" do
46
+ @doc.config['font_loader'][0] = 'UnknownFontLoader'
47
+ assert_raises(HexaPDF::Error) { @doc.fonts.add(:Other) }
48
+ end
49
+ end
50
+
51
+ it "returns the configured fonts" do
52
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::Standard14'
53
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::FromConfiguration'
54
+ @doc.config['font.map'] = {'Times' => {heavy: 'none', none: 'none'}, 'Other' => {none: 'none'}}
55
+ fonts = @doc.fonts.configured_fonts
56
+ assert_equal([:none], fonts['Symbol'])
57
+ assert_equal([:none, :bold, :italic, :bold_italic, :heavy], fonts['Times'])
58
+ assert_equal([:none], fonts['Other'])
59
+ end
60
+ end
@@ -0,0 +1,72 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'stringio'
5
+ require 'hexapdf/document'
6
+
7
+ describe HexaPDF::Document::Images do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ end
11
+
12
+ describe "add" do
13
+ describe "using a custom image loader" do
14
+ before do
15
+ @loader = Object.new
16
+ @loader.define_singleton_method(:handles?) {|*| true }
17
+ @loader.define_singleton_method(:load) do |doc, s|
18
+ s = HexaPDF::StreamData.new(s) if s.kind_of?(IO)
19
+ doc.add({Type: :XObject, Subtype: :Image}, stream: s)
20
+ end
21
+ @doc.config['image_loader'].unshift(@loader)
22
+ end
23
+
24
+ it "adds an image using a filename" do
25
+ data = 'test'
26
+ image = @doc.images.add(data)
27
+ assert_equal(data, image.stream)
28
+ assert_equal(File.absolute_path(data), image.source_path)
29
+ end
30
+
31
+ it "adds an image using an IO" do
32
+ File.open(__FILE__, 'rb') do |file|
33
+ image = @doc.images.add(file)
34
+ assert_equal(File.read(__FILE__), image.stream)
35
+ assert_equal(File.absolute_path(__FILE__), image.source_path)
36
+ end
37
+ end
38
+
39
+ it "doesn't add an image twice" do
40
+ data = 'test'
41
+ image = @doc.images.add(data)
42
+ image1 = @doc.images.add(data)
43
+ assert_same(image, image1)
44
+ end
45
+ end
46
+
47
+ it "fails if the needed image loader can't be resolved" do
48
+ @doc.config['image_loader'].unshift('SomeUnknownConstantHere')
49
+ exp = assert_raises(HexaPDF::Error) { @doc.images.add(StringIO.new('test')) }
50
+ assert_match(/image loader from configuration/, exp.message)
51
+ end
52
+
53
+ it "fails if no image loader is found" do
54
+ exp = assert_raises(HexaPDF::Error) { @doc.images.add(StringIO.new('test')) }
55
+ assert_match(/suitable image loader/, exp.message)
56
+ end
57
+ end
58
+
59
+ describe "each" do
60
+ it "iterates over all non-mask images" do
61
+ @doc.add(5)
62
+ images = []
63
+ images << @doc.add({Type: :XObject, Subtype: :Image})
64
+ images << @doc.add({Type: :XObject, Subtype: :Image, Mask: [5, 6]})
65
+ images << @doc.add({Type: :XObject, Subtype: :Image,
66
+ Mask: @doc.add({Type: :XObject, Subtype: :Image})})
67
+ images << @doc.add({Type: :XObject, Subtype: :Image,
68
+ SMask: @doc.add({Type: :XObject, Subtype: :Image})})
69
+ assert_equal(images.sort, @doc.images.to_a.sort)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,130 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/document'
5
+
6
+ describe HexaPDF::Document::Pages do
7
+ before do
8
+ @doc = HexaPDF::Document.new
9
+ end
10
+
11
+ describe "root" do
12
+ it "returns the root of the page tree" do
13
+ assert_same(@doc.catalog.pages, @doc.pages.root)
14
+ end
15
+ end
16
+
17
+ describe "add" do
18
+ it "adds a new empty page when no page is given" do
19
+ page = @doc.pages.add
20
+ assert_equal([page], @doc.pages.root[:Kids].value)
21
+ end
22
+
23
+ it "adds a new empty page with the given dimensions" do
24
+ page = @doc.pages.add([0, 0, 20, 20])
25
+ assert_same(page, @doc.pages[0])
26
+ assert_equal([0, 0, 20, 20], @doc.pages[0].box(:media).value)
27
+ end
28
+
29
+ it "adds a new empty page with the given page format" do
30
+ page = @doc.pages.add(:A4, orientation: :landscape)
31
+ assert_same(page, @doc.pages[0])
32
+ assert_equal([0, 0, 842, 595], @doc.pages[0].box(:media).value)
33
+ end
34
+
35
+ it "adds the given page to the end" do
36
+ page = @doc.pages.add
37
+ new_page = @doc.add({Type: :Page})
38
+ assert_same(new_page, @doc.pages.add(new_page))
39
+ assert_equal([page, new_page], @doc.pages.root[:Kids].value)
40
+ end
41
+
42
+ it "fails if an unknown page format is given" do
43
+ assert_raises(HexaPDF::Error) { @doc.pages.add(:A953) }
44
+ end
45
+ end
46
+
47
+ describe "<<" do
48
+ it "works like add but always needs a page returns self" do
49
+ page1 = @doc.add({Type: :Page})
50
+ page2 = @doc.add({Type: :Page})
51
+ @doc.pages << page1 << page2
52
+ assert_equal([page1, page2], @doc.pages.root[:Kids].value)
53
+ end
54
+ end
55
+
56
+ describe "insert" do
57
+ before do
58
+ @doc.pages.add
59
+ @doc.pages.add
60
+ @doc.pages.add
61
+ end
62
+
63
+ it "insert a new page at a given index" do
64
+ page = @doc.pages.insert(2)
65
+ assert_equal(page, @doc.pages.root[:Kids][2])
66
+ end
67
+
68
+ it "insert a given page at a given index" do
69
+ new_page = @doc.add({Type: :Page})
70
+ assert_same(new_page, @doc.pages.insert(2, new_page))
71
+ assert_equal(new_page, @doc.pages.root[:Kids][2])
72
+ end
73
+ end
74
+
75
+ describe "delete" do
76
+ it "deletes a given page" do
77
+ page1 = @doc.pages.add
78
+ page2 = @doc.pages.add
79
+
80
+ @doc.pages.delete(page1)
81
+ assert_equal([page2], @doc.pages.root[:Kids].value)
82
+ end
83
+ end
84
+
85
+ describe "delete_at" do
86
+ it "deletes a page at a given index" do
87
+ page1 = @doc.pages.add
88
+ @doc.pages.add
89
+ page3 = @doc.pages.add
90
+ @doc.pages.delete_at(1)
91
+ assert_equal([page1, page3], @doc.pages.root[:Kids].value)
92
+ end
93
+ end
94
+
95
+ describe "[]" do
96
+ it "returns the page at the given index" do
97
+ page1 = @doc.pages.add
98
+ page2 = @doc.pages.add
99
+ page3 = @doc.pages.add
100
+
101
+ assert_equal(page1, @doc.pages[0])
102
+ assert_equal(page2, @doc.pages[1])
103
+ assert_equal(page3, @doc.pages[2])
104
+ assert_nil(@doc.pages[3])
105
+ assert_equal(page3, @doc.pages[-1])
106
+ assert_equal(page2, @doc.pages[-2])
107
+ assert_equal(page1, @doc.pages[-3])
108
+ assert_nil(@doc.pages[-4])
109
+ end
110
+ end
111
+
112
+ describe "each" do
113
+ it "iterates over all pages" do
114
+ page1 = @doc.pages.add
115
+ page2 = @doc.pages.add
116
+ page3 = @doc.pages.add
117
+ assert_equal([page1, page2, page3], @doc.pages.to_a)
118
+ end
119
+ end
120
+
121
+ describe "count" do
122
+ it "returns the number of pages in the page tree" do
123
+ assert_equal(0, @doc.pages.count)
124
+ @doc.pages.add
125
+ @doc.pages.add
126
+ @doc.pages.add
127
+ assert_equal(3, @doc.pages.count)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,87 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+
5
+ # Contains tests that validate that an encryption algorithm's class conforms to the general
6
+ # interface.
7
+ #
8
+ # The algorithm class needs to be available in the @algorithm_class variable.
9
+ module EncryptionAlgorithmInterfaceTests
10
+
11
+ def test_responds_to_necessary_methods
12
+ [:encrypt, :decrypt, :encryption_fiber, :decryption_fiber].each do |method|
13
+ assert_respond_to(@algorithm_class, method)
14
+ assert_equal(2, @algorithm_class.method(method).arity)
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ # Contains common tests for AES algorithms.
21
+ #
22
+ # The algorithm class needs to be available in the @algorithm_class variable.
23
+ module AESEncryptionTests
24
+
25
+ include EncryptionAlgorithmInterfaceTests
26
+
27
+ TEST_VECTOR_FILES = Dir[File.join(TEST_DATA_DIR, 'aes-test-vectors', '*')]
28
+
29
+ def test_processes_the_aes_test_vectors
30
+ TEST_VECTOR_FILES.each do |filename|
31
+ name, size, mode = File.basename(filename, '.data.gz').split('-')
32
+ size = size.to_i / 8
33
+ data = Zlib::GzipReader.open(filename, &:read).force_encoding(Encoding::BINARY)
34
+ data.scan(/(.{#{size}})(.{16})(.{16})(.{16})/m).each_with_index do |(key, iv, plain, cipher), index|
35
+ aes = @algorithm_class.new(key, iv, mode.intern)
36
+ assert_equal(cipher, aes.process(plain),
37
+ "name: #{name}, size: #{size * 8}, mode: #{mode}, index: #{index}")
38
+ end
39
+ end
40
+ end
41
+
42
+ def test_can_accept_one_big_chunk_or_multiple_smaller_ones
43
+ big = @algorithm_class.new('t' * 16, '0' * 16, :encrypt)
44
+ small = @algorithm_class.new('t' * 16, '0' * 16, :encrypt)
45
+ assert_equal(big.process('some' * 16),
46
+ small.process('some' * 8) << small.process('some' * 4) << small.process('some' * 4))
47
+ end
48
+
49
+ def test_raises_error_on_invalid_key_length
50
+ assert_raises(HexaPDF::EncryptionError) { @algorithm_class.new('t' * 7, '0' * 16, :encrypt) }
51
+ end
52
+
53
+ def test_raises_error_on_invalid_iv_length
54
+ assert_raises(HexaPDF::EncryptionError) { @algorithm_class.new('t' * 16, '0' * 7, :encrypt) }
55
+ end
56
+
57
+ end
58
+
59
+ # Contains common tests for AES algorithms.
60
+ #
61
+ # The algorithm class needs to be available in the @algorithm_class variable.
62
+ module ARC4EncryptionTests
63
+
64
+ include EncryptionAlgorithmInterfaceTests
65
+
66
+ def setup
67
+ super
68
+ @encrypted = ['BBF316E8D940AF0AD3', '1021BF0420', '45A01F645FC35B383552544B9BF5'].
69
+ map {|c| [c].pack('H*') }
70
+ @plain = ['Plaintext', 'pedia', 'Attack at dawn'].each {|s| s.force_encoding('BINARY') }
71
+ @keys = ['Key', 'Wiki', 'Secret']
72
+ end
73
+
74
+ def test_processes_the_test_vectors_from_the_rc4_wikipeda_page
75
+ @keys.each_with_index do |key, i|
76
+ assert_equal(@encrypted[i], @algorithm_class.new(key).process(@plain[i]))
77
+ end
78
+ end
79
+
80
+ def test_can_accept_one_big_chunk_or_multiple_smaller_ones
81
+ big = @algorithm_class.new('key')
82
+ small = @algorithm_class.new('key')
83
+ assert_equal(big.process('some big data chunk'),
84
+ small.process('some') << small.process(' big') << small.process(' data chunk'))
85
+ end
86
+
87
+ end