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.
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