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,619 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/content/operator'
5
+ require 'hexapdf/content/processor'
6
+ require 'hexapdf/serializer'
7
+
8
+ describe HexaPDF::Content::Operator::BaseOperator do
9
+ before do
10
+ @op = HexaPDF::Content::Operator::BaseOperator.new('name')
11
+ end
12
+
13
+ it "takes a name on initialization and can return it" do
14
+ assert_equal('name', @op.name)
15
+ assert(@op.name.frozen?)
16
+ end
17
+
18
+ it "responds to invoke" do
19
+ assert_respond_to(@op, :invoke)
20
+ end
21
+
22
+ it "can serialize any operator with its operands" do
23
+ serializer = HexaPDF::Serializer.new
24
+ assert_equal("5.0 5 /Name name\n", @op.serialize(serializer, 5.0, 5, :Name))
25
+ end
26
+ end
27
+
28
+ describe HexaPDF::Content::Operator::NoArgumentOperator do
29
+ it "provides a special serialize method" do
30
+ op = HexaPDF::Content::Operator::NoArgumentOperator.new('name')
31
+ assert_equal("name\n", op.serialize(nil))
32
+ end
33
+ end
34
+
35
+ describe HexaPDF::Content::Operator::SingleNumericArgumentOperator do
36
+ it "provides a special serialize method" do
37
+ op = HexaPDF::Content::Operator::SingleNumericArgumentOperator.new('name')
38
+ serializer = HexaPDF::Serializer.new
39
+ assert_equal("5 name\n", op.serialize(serializer, 5))
40
+ assert_equal("5.45 name\n", op.serialize(serializer, 5.45))
41
+ end
42
+ end
43
+
44
+ module CommonOperatorTests
45
+ extend Minitest::Spec::DSL
46
+
47
+ before do
48
+ resources = {}
49
+ resources.define_singleton_method(:color_space) do |name|
50
+ HexaPDF::GlobalConfiguration.constantize('color_space.map', name).new
51
+ end
52
+ resources.define_singleton_method(:ext_gstate) do |name|
53
+ self[:ExtGState] && self[:ExtGState][name] || raise(HexaPDF::Error, "missing")
54
+ end
55
+ @processor = HexaPDF::Content::Processor.new(resources)
56
+ @serializer = HexaPDF::Serializer.new
57
+ end
58
+
59
+ # calls the method of the operator with the operands
60
+ def call(method, *operands)
61
+ HexaPDF::Content::Operator::DEFAULT_OPERATORS[@name].send(method, *operands)
62
+ end
63
+
64
+ # calls the invoke method on the operator
65
+ def invoke(*operands)
66
+ call(:invoke, @processor, *operands)
67
+ end
68
+
69
+ it "is associated with the correct operator name in the default mapping" do
70
+ assert_equal(@name, call(:name).to_sym)
71
+ end
72
+
73
+ it "is not the base operator implementation" do
74
+ refute_equal(HexaPDF::Content::Operator::BaseOperator, call(:class))
75
+ end
76
+
77
+ def assert_serialized(*operands)
78
+ op = HexaPDF::Content::Operator::BaseOperator.new(@name.to_s)
79
+ assert_equal(op.serialize(@serializer, *operands), call(:serialize, @serializer, *operands))
80
+ end
81
+
82
+ end
83
+
84
+ def describe_operator(name, symbol, &block)
85
+ klass_name = "HexaPDF::Content::Operator::#{name}"
86
+ klass = describe(klass_name, &block)
87
+ klass.send(:include, CommonOperatorTests)
88
+ one_time_module = Module.new
89
+ one_time_module.send(:define_method, :setup) do
90
+ super()
91
+ @name = symbol
92
+ end
93
+ one_time_module.send(:define_method, :test_class_name) do
94
+ assert_equal(klass_name, call(:class).name)
95
+ end
96
+ klass.send(:include, one_time_module)
97
+ klass
98
+ end
99
+
100
+ describe_operator :SaveGraphicsState, :q do
101
+ it "saves the graphics state" do
102
+ width = @processor.graphics_state.line_width
103
+ invoke
104
+ @processor.graphics_state.line_width = 10
105
+ @processor.graphics_state.restore
106
+ assert_equal(width, @processor.graphics_state.line_width)
107
+ end
108
+ end
109
+
110
+ describe_operator :RestoreGraphicsState, :Q do
111
+ it "restores the graphics state" do
112
+ width = @processor.graphics_state.line_width
113
+ @processor.graphics_state.save
114
+ @processor.graphics_state.line_width = 10
115
+ invoke
116
+ assert_equal(width, @processor.graphics_state.line_width)
117
+ end
118
+ end
119
+
120
+ describe_operator :ConcatenateMatrix, :cm do
121
+ it "concatenates the ctm by pre-multiplication" do
122
+ invoke(1, 2, 3, 4, 5, 6)
123
+ invoke(6, 5, 4, 3, 2, 1)
124
+ assert_equal(21, @processor.graphics_state.ctm.a)
125
+ assert_equal(32, @processor.graphics_state.ctm.b)
126
+ assert_equal(13, @processor.graphics_state.ctm.c)
127
+ assert_equal(20, @processor.graphics_state.ctm.d)
128
+ assert_equal(10, @processor.graphics_state.ctm.e)
129
+ assert_equal(14, @processor.graphics_state.ctm.f)
130
+ end
131
+
132
+ it "serializes correctly" do
133
+ assert_serialized(1, 2, 3, 4, 5, 6)
134
+ end
135
+ end
136
+
137
+ describe_operator :SetLineWidth, :w do
138
+ it "sets the line width" do
139
+ invoke(10)
140
+ assert_equal(10, @processor.graphics_state.line_width)
141
+ end
142
+ end
143
+
144
+ describe_operator :SetLineCapStyle, :J do
145
+ it "sets the line cap" do
146
+ invoke(HexaPDF::Content::LineCapStyle::ROUND_CAP)
147
+ assert_equal(HexaPDF::Content::LineCapStyle::ROUND_CAP,
148
+ @processor.graphics_state.line_cap_style)
149
+ end
150
+ end
151
+
152
+ describe_operator :SetLineJoinStyle, :j do
153
+ it "sets the line join" do
154
+ invoke(HexaPDF::Content::LineJoinStyle::ROUND_JOIN)
155
+ assert_equal(HexaPDF::Content::LineJoinStyle::ROUND_JOIN,
156
+ @processor.graphics_state.line_join_style)
157
+ end
158
+ end
159
+
160
+ describe_operator :SetMiterLimit, :M do
161
+ it "sets the miter limit" do
162
+ invoke(100)
163
+ assert_equal(100, @processor.graphics_state.miter_limit)
164
+ end
165
+ end
166
+
167
+ describe_operator :SetLineDashPattern, :d do
168
+ it "sets the line dash pattern" do
169
+ invoke([3, 4], 5)
170
+ assert_equal(HexaPDF::Content::LineDashPattern.new([3, 4], 5),
171
+ @processor.graphics_state.line_dash_pattern)
172
+ end
173
+
174
+ it "serializes correctly" do
175
+ assert_serialized([3, 4], 5)
176
+ end
177
+ end
178
+
179
+ describe_operator :SetRenderingIntent, :ri do
180
+ it "sets the rendering intent" do
181
+ invoke(HexaPDF::Content::RenderingIntent::SATURATION)
182
+ assert_equal(HexaPDF::Content::RenderingIntent::SATURATION,
183
+ @processor.graphics_state.rendering_intent)
184
+ end
185
+
186
+ it "serializes correctly" do
187
+ assert_serialized(HexaPDF::Content::RenderingIntent::SATURATION)
188
+ end
189
+ end
190
+
191
+ describe_operator :SetGraphicsStateParameters, :gs do
192
+ it "applies parameters from an ExtGState dictionary" do
193
+ @processor.resources[:ExtGState] = {Name: {LW: 10, LC: 2, LJ: 2, ML: 2, D: [[3, 5], 2],
194
+ RI: 2, SA: true, BM: :Multiply, CA: 0.5, ca: 0.5,
195
+ AIS: true, TK: false, Font: [:Test, 10]}}
196
+ @processor.resources.define_singleton_method(:document) do
197
+ Object.new.tap {|obj| obj.define_singleton_method(:deref) {|o| o } }
198
+ end
199
+
200
+ invoke(:Name)
201
+ gs = @processor.graphics_state
202
+ assert_equal(10, gs.line_width)
203
+ assert_equal(2, gs.line_cap_style)
204
+ assert_equal(2, gs.line_join_style)
205
+ assert_equal(2, gs.miter_limit)
206
+ assert_equal(HexaPDF::Content::LineDashPattern.new([3, 5], 2), gs.line_dash_pattern)
207
+ assert_equal(2, gs.rendering_intent)
208
+ assert(gs.stroke_adjustment)
209
+ assert_equal(:Multiply, gs.blend_mode)
210
+ assert_equal(0.5, gs.stroke_alpha)
211
+ assert_equal(0.5, gs.fill_alpha)
212
+ assert(gs.alpha_source)
213
+ assert_equal(:Test, gs.font)
214
+ assert_equal(10, gs.font_size)
215
+ refute(gs.text_knockout)
216
+ end
217
+
218
+ it "fails if the resources dictionary doesn't have an ExtGState entry" do
219
+ assert_raises(HexaPDF::Error) { invoke(:Name) }
220
+ end
221
+
222
+ it "fails if the ExtGState resources doesn't have the specified dictionary" do
223
+ @processor.resources[:ExtGState] = {}
224
+ assert_raises(HexaPDF::Error) { invoke(:Name) }
225
+ end
226
+
227
+ it "serializes correctly" do
228
+ assert_serialized(:Name)
229
+ end
230
+ end
231
+
232
+ describe_operator :SetStrokingColorSpace, :CS do
233
+ it "sets the stroking color space" do
234
+ invoke(:DeviceRGB)
235
+ assert_equal(@processor.resources.color_space(:DeviceRGB), @processor.graphics_state.stroke_color_space)
236
+ end
237
+
238
+ it "serializes correctly" do
239
+ assert_serialized(:DeviceRGB)
240
+ end
241
+ end
242
+
243
+ describe_operator :SetNonStrokingColorSpace, :cs do
244
+ it "sets the non stroking color space" do
245
+ invoke(:DeviceRGB)
246
+ assert_equal(@processor.resources.color_space(:DeviceRGB),
247
+ @processor.graphics_state.fill_color_space)
248
+ end
249
+
250
+ it "serializes correctly" do
251
+ assert_serialized(:DeviceRGB)
252
+ end
253
+ end
254
+
255
+ describe_operator :SetStrokingColor, :SC do
256
+ it "sets the stroking color" do
257
+ invoke(0.2)
258
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
259
+ @processor.graphics_state.stroke_color)
260
+ end
261
+
262
+ it "serializes correctly" do
263
+ assert_serialized(0.2, 0.5, 0.8)
264
+ end
265
+ end
266
+
267
+ describe_operator :SetNonStrokingColor, :sc do
268
+ it "sets the non stroking color" do
269
+ invoke(0.2)
270
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
271
+ @processor.graphics_state.fill_color)
272
+ end
273
+
274
+ it "serializes correctly" do
275
+ assert_serialized(0.2, 0.5, 0.8)
276
+ end
277
+ end
278
+
279
+ describe_operator :SetDeviceGrayStrokingColor, :G do
280
+ it "sets the DeviceGray stroking color" do
281
+ invoke(0.2)
282
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
283
+ @processor.graphics_state.stroke_color)
284
+ end
285
+ end
286
+
287
+ describe_operator :SetDeviceGrayNonStrokingColor, :g do
288
+ it "sets the DeviceGray non stroking color" do
289
+ invoke(0.2)
290
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
291
+ @processor.graphics_state.fill_color)
292
+ end
293
+ end
294
+
295
+ describe_operator :SetDeviceRGBStrokingColor, :RG do
296
+ it "sets the DeviceRGB stroking color" do
297
+ invoke(0.2, 0, 0.2)
298
+ assert_equal(@processor.resources.color_space(:DeviceRGB).color(51, 0, 51),
299
+ @processor.graphics_state.stroke_color)
300
+ end
301
+
302
+ it "serializes correctly" do
303
+ assert_serialized(0.2, 0.3, 0.4)
304
+ end
305
+ end
306
+
307
+ describe_operator :SetDeviceRGBNonStrokingColor, :rg do
308
+ it "sets the DeviceRGB non stroking color" do
309
+ invoke(0.2, 0, 0.2)
310
+ assert_equal(@processor.resources.color_space(:DeviceRGB).color(51, 0, 51),
311
+ @processor.graphics_state.fill_color)
312
+ end
313
+
314
+ it "serializes correctly" do
315
+ assert_serialized(0.2, 0.3, 0.4)
316
+ end
317
+ end
318
+
319
+ describe_operator :SetDeviceCMYKStrokingColor, :K do
320
+ it "sets the DeviceCMYK stroking color" do
321
+ invoke(0.51, 0, 0.51, 0.51)
322
+ assert_equal(@processor.resources.color_space(:DeviceCMYK).color(51, 0, 51, 51),
323
+ @processor.graphics_state.stroke_color)
324
+ end
325
+
326
+ it "serializes correctly" do
327
+ assert_serialized(0.2, 0.3, 0.4, 0.5)
328
+ end
329
+ end
330
+
331
+ describe_operator :SetDeviceCMYKNonStrokingColor, :k do
332
+ it "sets the DeviceCMYK non stroking color" do
333
+ invoke(0.51, 0, 0.51, 0.51)
334
+ assert_equal(@processor.resources.color_space(:DeviceCMYK).color(51, 0, 51, 51),
335
+ @processor.graphics_state.fill_color)
336
+ end
337
+
338
+ it "serializes correctly" do
339
+ assert_serialized(0.2, 0.3, 0.4, 0.5)
340
+ end
341
+ end
342
+
343
+ describe_operator :MoveTo, :m do
344
+ it "changes the graphics object to path" do
345
+ refute_equal(:path, @processor.graphics_object)
346
+ invoke(128, 0)
347
+ assert_equal(:path, @processor.graphics_object)
348
+ end
349
+
350
+ it "serializes correctly" do
351
+ assert_serialized(1.54, 1.78)
352
+ end
353
+ end
354
+
355
+ describe_operator :AppendRectangle, :re do
356
+ it "changes the graphics object to path" do
357
+ refute_equal(:path, @processor.graphics_object)
358
+ invoke(128, 0, 10, 10)
359
+ assert_equal(:path, @processor.graphics_object)
360
+ end
361
+
362
+ it "serializes correctly" do
363
+ assert_serialized(10, 11, 1.54, 1.78)
364
+ end
365
+ end
366
+
367
+ describe_operator :LineTo, :l do
368
+ it "serializes correctly" do
369
+ assert_serialized(1.54, 1.78)
370
+ end
371
+ end
372
+
373
+ describe_operator :CurveTo, :c do
374
+ it "serializes correctly" do
375
+ assert_serialized(1.54, 1.78, 2, 3, 5, 6)
376
+ end
377
+ end
378
+
379
+ describe_operator :CurveToNoFirstControlPoint, :v do
380
+ it "serializes correctly" do
381
+ assert_serialized(2, 3, 5, 6)
382
+ end
383
+ end
384
+
385
+ describe_operator :CurveToNoSecondControlPoint, :y do
386
+ it "serializes correctly" do
387
+ assert_serialized(2, 3, 5, 6)
388
+ end
389
+ end
390
+
391
+ [:S, :s, :f, :F, 'f*'.intern, :B, 'B*'.intern, :b, 'b*'.intern, :n].each do |sym|
392
+ describe_operator :EndPath, sym do
393
+ it "changes the graphics object to none" do
394
+ @processor.graphics_object = :path
395
+ invoke
396
+ refute_equal(:path, @processor.graphics_object)
397
+ end
398
+ end
399
+ end
400
+
401
+ [:W, 'W*'.intern].each do |sym|
402
+ describe_operator :ClipPath, sym do
403
+ it "changes the graphics object to clipping_path for clip path operations" do
404
+ invoke
405
+ assert_equal(:clipping_path, @processor.graphics_object)
406
+ end
407
+ end
408
+ end
409
+
410
+ describe_operator :InlineImage, :BI do
411
+ it "serializes correctly" do
412
+ assert_equal("BI\n/Name 5 /OP 6 ID\nsome dataEI\n",
413
+ call(:serialize, @serializer, {Name: 5, OP: 6}, 'some data'))
414
+ end
415
+ end
416
+
417
+ describe_operator :SetCharacterSpacing, :Tc do
418
+ it "modifies the character spacing" do
419
+ invoke(127)
420
+ assert_equal(127, @processor.graphics_state.character_spacing)
421
+ end
422
+ end
423
+
424
+ describe_operator :SetWordSpacing, :Tw do
425
+ it "modifies the word spacing" do
426
+ invoke(127)
427
+ assert_equal(127, @processor.graphics_state.word_spacing)
428
+ end
429
+ end
430
+
431
+ describe_operator :SetHorizontalScaling, :Tz do
432
+ it "modifies the horizontal scaling parameter" do
433
+ invoke(127)
434
+ assert_equal(127, @processor.graphics_state.horizontal_scaling)
435
+ end
436
+ end
437
+
438
+ describe_operator :SetLeading, :TL do
439
+ it "modifies the leading parameter" do
440
+ invoke(127)
441
+ assert_equal(127, @processor.graphics_state.leading)
442
+ end
443
+ end
444
+
445
+ describe_operator :SetFontAndSize, :Tf do
446
+ it "sets the font and size correctly" do
447
+ @processor.resources.define_singleton_method(:font) do |name|
448
+ self[:Font] && self[:Font][name]
449
+ end
450
+
451
+ @processor.resources[:Font] = {F1: :test}
452
+ invoke(:F1, 10)
453
+ assert_equal(@processor.resources.font(:F1), @processor.graphics_state.font)
454
+ assert_equal(10, @processor.graphics_state.font_size)
455
+ end
456
+
457
+ it "serializes correctly" do
458
+ assert_serialized(:Font, 1.78)
459
+ end
460
+ end
461
+
462
+ describe_operator :SetTextRenderingMode, :Tr do
463
+ it "modifies the text rendering mode" do
464
+ invoke(HexaPDF::Content::TextRenderingMode::FILL_STROKE)
465
+ assert_equal(HexaPDF::Content::TextRenderingMode::FILL_STROKE,
466
+ @processor.graphics_state.text_rendering_mode)
467
+ end
468
+ end
469
+
470
+ describe_operator :SetTextRise, :Ts do
471
+ it "modifies the text rise" do
472
+ invoke(127)
473
+ assert_equal(127, @processor.graphics_state.text_rise)
474
+ end
475
+ end
476
+
477
+ describe_operator :BeginText, :BT do
478
+ it "changes the graphics object to text and the tm/tlm to the identity matrix" do
479
+ @processor.graphics_object = :none
480
+ invoke
481
+ assert_equal(:text, @processor.graphics_object)
482
+ assert_equal(HexaPDF::Content::TransformationMatrix.new, @processor.graphics_state.tm)
483
+ assert_equal(HexaPDF::Content::TransformationMatrix.new, @processor.graphics_state.tlm)
484
+ end
485
+ end
486
+
487
+ describe_operator :EndText, :ET do
488
+ it "changes the graphics object to :none and undefines the text and text line matrices" do
489
+ @processor.graphics_object = :text
490
+ invoke
491
+ assert_equal(:none, @processor.graphics_object)
492
+ assert_nil(@processor.graphics_state.tm)
493
+ assert_nil(@processor.graphics_state.tlm)
494
+ end
495
+ end
496
+
497
+ describe_operator :MoveText, :Td do
498
+ it "correctly updates the text and text line matrices" do
499
+ @processor.graphics_state.tm = HexaPDF::Content::TransformationMatrix.new
500
+ @processor.graphics_state.tlm = HexaPDF::Content::TransformationMatrix.new
501
+ invoke(5, 10)
502
+ assert_equal(HexaPDF::Content::TransformationMatrix.new(1, 0, 0, 1, 5, 10),
503
+ @processor.graphics_state.tm)
504
+ assert_equal(HexaPDF::Content::TransformationMatrix.new(1, 0, 0, 1, 5, 10),
505
+ @processor.graphics_state.tlm)
506
+ end
507
+
508
+ it "serializes correctly" do
509
+ assert_serialized(1.54, 1.78)
510
+ end
511
+ end
512
+
513
+ describe_operator :MoveTextAndSetLeading, :TD do
514
+ it "invokes the TL and Td operators" do
515
+ tl = Minitest::Mock.new
516
+ tl.expect(:invoke, nil, [@processor, -1.78])
517
+ @processor.operators[:TL] = tl
518
+ td = Minitest::Mock.new
519
+ td.expect(:invoke, nil, [@processor, 1.56, 1.78])
520
+ @processor.operators[:Td] = td
521
+
522
+ invoke(1.56, 1.78)
523
+ assert(tl.verify)
524
+ assert(td.verify)
525
+ end
526
+
527
+ it "serializes correctly" do
528
+ assert_serialized(1.54, 1.78)
529
+ end
530
+ end
531
+
532
+ describe_operator :SetTextMatrix, :Tm do
533
+ it "correctly sets the text and text line matrices" do
534
+ @processor.graphics_state.tm = HexaPDF::Content::TransformationMatrix.new
535
+ @processor.graphics_state.tlm = HexaPDF::Content::TransformationMatrix.new
536
+ invoke(2, 3, 4, 5, 6, 7)
537
+ assert_equal(HexaPDF::Content::TransformationMatrix.new(2, 3, 4, 5, 6, 7),
538
+ @processor.graphics_state.tm)
539
+ assert_equal(HexaPDF::Content::TransformationMatrix.new(2, 3, 4, 5, 6, 7),
540
+ @processor.graphics_state.tlm)
541
+ end
542
+
543
+ it "serializes correctly" do
544
+ assert_serialized(1, 2, 3, 4, 5, 6)
545
+ end
546
+ end
547
+
548
+ describe_operator :MoveTextNextLine, :'T*' do
549
+ it "invokes the Td operator" do
550
+ td = Minitest::Mock.new
551
+ td.expect(:invoke, nil, [@processor, 0, -1.78])
552
+ @processor.operators[:Td] = td
553
+
554
+ @processor.graphics_state.leading = 1.78
555
+ invoke
556
+ assert(td.verify)
557
+ end
558
+ end
559
+
560
+ describe_operator :ShowText, :Tj do
561
+ it "serializes correctly" do
562
+ assert_equal("(Some Text)Tj\n", call(:serialize, @serializer, "Some Text"))
563
+ end
564
+ end
565
+
566
+ describe_operator :MoveTextNextLineAndShowText, :"'" do
567
+ it "invokes the T* and Tj operators" do
568
+ text = "Some text"
569
+
570
+ tstar = Minitest::Mock.new
571
+ tstar.expect(:invoke, nil, [@processor])
572
+ @processor.operators[:'T*'] = tstar
573
+ tj = Minitest::Mock.new
574
+ tj.expect(:invoke, nil, [@processor, text])
575
+ @processor.operators[:Tj] = tj
576
+
577
+ invoke(text)
578
+ assert(tstar.verify)
579
+ assert(tj.verify)
580
+ end
581
+
582
+ it "serializes correctly" do
583
+ assert_equal("(Some Text)'\n", call(:serialize, @serializer, "Some Text"))
584
+ end
585
+ end
586
+
587
+ describe_operator :SetSpacingMoveTextNextLineAndShowText, :'"' do
588
+ it "invokes the Tw, Tc and ' operators" do
589
+ word_spacing = 10
590
+ char_spacing = 15
591
+ text = "Some text"
592
+
593
+ tw = Minitest::Mock.new
594
+ tw.expect(:invoke, nil, [@processor, word_spacing])
595
+ @processor.operators[:Tw] = tw
596
+ tc = Minitest::Mock.new
597
+ tc.expect(:invoke, nil, [@processor, char_spacing])
598
+ @processor.operators[:Tc] = tc
599
+ tapos = Minitest::Mock.new
600
+ tapos.expect(:invoke, nil, [@processor, text])
601
+ @processor.operators[:"'"] = tapos
602
+
603
+ invoke(word_spacing, char_spacing, text)
604
+ assert(tw.verify)
605
+ assert(tc.verify)
606
+ assert(tapos.verify)
607
+ end
608
+
609
+ it "serializes correctly" do
610
+ assert_equal("10 15 (Some Text)\"\n", call(:serialize, @serializer, 10, 15, "Some Text"))
611
+ end
612
+ end
613
+
614
+ describe_operator :ShowTextWithPositioning, :TJ do
615
+ it "serializes correctly" do
616
+ assert_equal("[(Some Text)15(other text)20(final text)]TJ\n",
617
+ call(:serialize, @serializer, ["Some Text", 15, "other text", 20, "final text"]))
618
+ end
619
+ end
@@ -0,0 +1,99 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/content/parser'
5
+ require 'hexapdf/content/processor'
6
+ require_relative '../common_tokenizer_tests'
7
+ require_relative 'common'
8
+
9
+ describe HexaPDF::Content::Tokenizer do
10
+ include CommonTokenizerTests
11
+
12
+ def create_tokenizer(str)
13
+ @tokenizer = HexaPDF::Content::Tokenizer.new(str.b)
14
+ end
15
+ end
16
+
17
+ describe HexaPDF::Content::Parser do
18
+ before do
19
+ @processor = TestHelper::OperatorRecorder.new
20
+ @parser = HexaPDF::Content::Parser.new
21
+ end
22
+
23
+ describe "parse" do
24
+ before do
25
+ @image_data = "x\x9Ccd\xC0\x00\xBB\x1F<\xC6\x14\xA43EI JP)\xB8w\xFDZ\xBA\xA7;Ae\xC4;u\xDB\xF2e\xFD\x95\xE5\x04\x95u/[a`e\x8DK\xD6UA\x96*\xEE\xD9\xBFyS[n6\xD9FQ\xCB\x19\x04\x8DZz\xEC\x84\x98\x944\xB2\bA\x97[\xB8\xB86\xCF\x99G\xA4\xED\x04\x1D\x90^]\e\x92\x9AF\x86FL\x97\x13\xAF\x17\b\n\xDB;\xBD\"\xA3\xF0\xAB\x01\x82\xDA\x94\xA4\x13{v\x13T\x86+:\x16\xF4v/\x9D<\x89rg\xE0J\xDBU\x93\xA7\xCA\xAB\xA8(ija\xD5EI\x00\xD2\bP%a\xD3-w\xCC\xDF\x7FPFQ\t\x97,\xC1\xC8%\xD2\x19X#\xD7':V\xCF\xC2\xC2\xCC\xC1\x91\x9B\x97\x97\x18CH\x02\xD4\n@br\a\x9EdF\xB93(\x89>\xEA\x1AB\x87\xC4@\xE7\x9CN\xD3\xB2\x8Bn>\xA2u\x1A#\xC6\x04\n\xC1\x93\xFB\xF7\x12\x1D\xEDq\xC9\x02C2\xBF\xB5\r\xBF\t\x94xa\xB4E\x84\x06^={\x1Ame\x81G\xC1\xEA\xB3\xE7\x05\x84E\xC8v\x00\xADk@\xFC\xC9\x89\x18\a\x10\xB4\x1D\x7F\x13\x91\xF2\x00\xA4\x1C\xE0\xF7\x021y\x8A\x81\xB8$=s\xFBN\\E\xDC\x9A\xD9\xB3f\xB66\x13\xB4\x85\x18\xC7\x10,\xAB\xF1\xF7z\x18\x06G\xC3\x8C*\x91B\x8C3\xF0D\nA\xED\x90\xF2\x01\x00_\x97\xE3\x80\n".b
26
+ end
27
+
28
+ it "parses a simple content stream without inline images" do
29
+ @parser.parse("0 0.500 m q Q /Name SCN", @processor)
30
+ assert_equal([[:move_to, [0, 0.5]], [:save_graphics_state],
31
+ [:restore_graphics_state],
32
+ [:set_stroking_color, [:Name]]], @processor.recorded_ops)
33
+ end
34
+
35
+ it "parses a content stream with an inline image without EI in image data" do
36
+ @parser.parse("q BI /Name 0.5/Other 1 ID some dataEI Q", @processor)
37
+ assert_equal([[:save_graphics_state],
38
+ [:inline_image, [{Name: 0.5, Other: 1}, "some data"]],
39
+ [:restore_graphics_state]], @processor.recorded_ops)
40
+ end
41
+
42
+ it "parses a content stream with an inline image with EI in image data" do
43
+ @parser.parse("BI\n/CS/RGB\nID #{@image_data}EI Q\nq 1308 0 0 1 485.996 4531.67 cm\n".b,
44
+ @processor)
45
+ assert_equal([[:inline_image, [{CS: :RGB}, @image_data]],
46
+ [:restore_graphics_state],
47
+ [:save_graphics_state],
48
+ [:concatenate_matrix, [1308, 0, 0, 1, 485.996, 4531.67]]],
49
+ @processor.recorded_ops)
50
+ end
51
+
52
+ it "parses a content stream with an inline image with EI in image data at end of stream" do
53
+ @parser.parse("BI\n/CS/RGB\nID #{@image_data}EI".b, @processor)
54
+ assert_equal([[:inline_image, [{CS: :RGB}, @image_data]]], @processor.recorded_ops)
55
+ end
56
+
57
+ it "fails parsing inline images if the dictionary keys are not PDF names" do
58
+ exp = assert_raises(HexaPDF::Error) do
59
+ @parser.parse("q BI /Name 0.5 Other 1 ID some dataEI Q", @processor)
60
+ end
61
+ assert_match(/keys.*PDF name/, exp.message)
62
+ end
63
+
64
+ it "fails parsing inline images when trying to read a dict key and EOS is encountered" do
65
+ exp = assert_raises(HexaPDF::Error) do
66
+ @parser.parse("q BI /Name 0.5", @processor)
67
+ end
68
+ assert_match(/EOS.*dictionary key/, exp.message)
69
+ end
70
+
71
+ it "fails parsing inline images when trying to read a dict value and EOS is encountered" do
72
+ exp = assert_raises(HexaPDF::Error) do
73
+ @parser.parse("q BI /Name 0.5 /Other", @processor)
74
+ end
75
+ assert_match(/EOS.*dictionary value/, exp.message)
76
+ end
77
+
78
+ it "fails parsing inline images if the EI is not found" do
79
+ exp = assert_raises(HexaPDF::Error) do
80
+ @parser.parse("q BI /Name 0.5 /Other 1 ID test", @processor)
81
+ end
82
+ assert_match(/EI not found/, exp.message)
83
+ end
84
+
85
+ it "can use a block instead of the processor object" do
86
+ called = 0
87
+ @parser.parse("/F1 5 Tf") do |obj, params|
88
+ called += 1
89
+ assert_equal(:Tf, obj)
90
+ assert_equal([:F1, 5], params)
91
+ end
92
+ assert_equal(1, called)
93
+ end
94
+
95
+ it "fails if neither a processor object or a block is provided" do
96
+ assert_raises(ArgumentError) { @parser.parse("test") }
97
+ end
98
+ end
99
+ end