hexapdf 0.11.7 → 0.12.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 +121 -0
  3. data/LICENSE +1 -1
  4. data/examples/001-hello_world.rb +1 -1
  5. data/examples/002-graphics.rb +1 -1
  6. data/examples/003-arcs.rb +1 -1
  7. data/examples/004-optimizing.rb +1 -1
  8. data/examples/005-merging.rb +1 -1
  9. data/examples/006-standard_pdf_fonts.rb +1 -1
  10. data/examples/007-truetype.rb +1 -1
  11. data/examples/008-show_char_bboxes.rb +1 -1
  12. data/examples/009-text_layouter_alignment.rb +1 -1
  13. data/examples/010-text_layouter_inline_boxes.rb +1 -1
  14. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  15. data/examples/012-text_layouter_styling.rb +1 -1
  16. data/examples/013-text_layouter_shapes.rb +1 -1
  17. data/examples/014-text_in_polygon.rb +1 -1
  18. data/examples/015-boxes.rb +1 -1
  19. data/examples/016-frame_automatic_box_placement.rb +1 -1
  20. data/examples/017-frame_text_flow.rb +1 -1
  21. data/examples/018-composer.rb +1 -1
  22. data/examples/019-acro_form.rb +51 -0
  23. data/lib/hexapdf.rb +1 -1
  24. data/lib/hexapdf/cli.rb +3 -1
  25. data/lib/hexapdf/cli/batch.rb +1 -1
  26. data/lib/hexapdf/cli/command.rb +18 -9
  27. data/lib/hexapdf/cli/files.rb +1 -1
  28. data/lib/hexapdf/cli/form.rb +240 -0
  29. data/lib/hexapdf/cli/image2pdf.rb +1 -1
  30. data/lib/hexapdf/cli/images.rb +1 -1
  31. data/lib/hexapdf/cli/info.rb +1 -1
  32. data/lib/hexapdf/cli/inspect.rb +1 -1
  33. data/lib/hexapdf/cli/merge.rb +1 -1
  34. data/lib/hexapdf/cli/modify.rb +1 -1
  35. data/lib/hexapdf/cli/optimize.rb +1 -1
  36. data/lib/hexapdf/cli/split.rb +1 -1
  37. data/lib/hexapdf/cli/watermark.rb +1 -1
  38. data/lib/hexapdf/composer.rb +2 -2
  39. data/lib/hexapdf/configuration.rb +66 -11
  40. data/lib/hexapdf/content.rb +3 -1
  41. data/lib/hexapdf/content/canvas.rb +5 -18
  42. data/lib/hexapdf/content/color_space.rb +111 -32
  43. data/lib/hexapdf/content/graphic_object.rb +1 -1
  44. data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
  45. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  46. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  47. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  48. data/lib/hexapdf/content/graphics_state.rb +1 -1
  49. data/lib/hexapdf/content/operator.rb +9 -9
  50. data/lib/hexapdf/content/parser.rb +18 -5
  51. data/lib/hexapdf/content/processor.rb +1 -1
  52. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  53. data/lib/hexapdf/data_dir.rb +1 -1
  54. data/lib/hexapdf/dictionary.rb +1 -1
  55. data/lib/hexapdf/dictionary_fields.rb +1 -1
  56. data/lib/hexapdf/document.rb +14 -5
  57. data/lib/hexapdf/document/files.rb +1 -1
  58. data/lib/hexapdf/document/fonts.rb +1 -1
  59. data/lib/hexapdf/document/images.rb +1 -1
  60. data/lib/hexapdf/document/pages.rb +3 -14
  61. data/lib/hexapdf/encryption.rb +1 -1
  62. data/lib/hexapdf/encryption/aes.rb +1 -1
  63. data/lib/hexapdf/encryption/arc4.rb +1 -1
  64. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  65. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  66. data/lib/hexapdf/encryption/identity.rb +1 -1
  67. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  68. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  69. data/lib/hexapdf/encryption/security_handler.rb +7 -1
  70. data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
  71. data/lib/hexapdf/error.rb +1 -1
  72. data/lib/hexapdf/filter.rb +3 -3
  73. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  74. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  75. data/lib/hexapdf/filter/encryption.rb +1 -1
  76. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  77. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  78. data/lib/hexapdf/filter/{jpx_decode.rb → pass_through.rb} +5 -5
  79. data/lib/hexapdf/filter/predictor.rb +1 -1
  80. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  81. data/lib/hexapdf/font/cmap.rb +1 -1
  82. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  83. data/lib/hexapdf/font/cmap/writer.rb +1 -1
  84. data/lib/hexapdf/font/encoding.rb +1 -1
  85. data/lib/hexapdf/font/encoding/base.rb +9 -1
  86. data/lib/hexapdf/font/encoding/difference_encoding.rb +7 -1
  87. data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
  88. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  89. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  90. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  91. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  92. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
  93. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  94. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  95. data/lib/hexapdf/font/true_type.rb +1 -1
  96. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  97. data/lib/hexapdf/font/true_type/font.rb +1 -1
  98. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  99. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  100. data/lib/hexapdf/font/true_type/table.rb +1 -1
  101. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  102. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  103. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  104. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  105. data/lib/hexapdf/font/true_type/table/head.rb +1 -1
  106. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  107. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  108. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  109. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  110. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  111. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  112. data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
  113. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  114. data/lib/hexapdf/font/true_type_wrapper.rb +54 -51
  115. data/lib/hexapdf/font/type1.rb +1 -1
  116. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  117. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  118. data/lib/hexapdf/font/type1/font.rb +1 -1
  119. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  120. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  121. data/lib/hexapdf/font/type1_wrapper.rb +68 -52
  122. data/lib/hexapdf/font_loader.rb +1 -1
  123. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  124. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  125. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  126. data/lib/hexapdf/image_loader.rb +1 -1
  127. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  128. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  129. data/lib/hexapdf/image_loader/png.rb +1 -1
  130. data/lib/hexapdf/importer.rb +2 -4
  131. data/lib/hexapdf/layout.rb +1 -1
  132. data/lib/hexapdf/layout/box.rb +1 -1
  133. data/lib/hexapdf/layout/frame.rb +1 -1
  134. data/lib/hexapdf/layout/image_box.rb +1 -1
  135. data/lib/hexapdf/layout/inline_box.rb +1 -1
  136. data/lib/hexapdf/layout/line.rb +1 -1
  137. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  138. data/lib/hexapdf/layout/style.rb +1 -1
  139. data/lib/hexapdf/layout/text_box.rb +1 -1
  140. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  141. data/lib/hexapdf/layout/text_layouter.rb +1 -1
  142. data/lib/hexapdf/layout/text_shaper.rb +1 -1
  143. data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
  144. data/lib/hexapdf/name_tree_node.rb +1 -1
  145. data/lib/hexapdf/number_tree_node.rb +1 -1
  146. data/lib/hexapdf/object.rb +2 -2
  147. data/lib/hexapdf/parser.rb +4 -3
  148. data/lib/hexapdf/pdf_array.rb +1 -1
  149. data/lib/hexapdf/rectangle.rb +31 -1
  150. data/lib/hexapdf/reference.rb +1 -1
  151. data/lib/hexapdf/revision.rb +2 -1
  152. data/lib/hexapdf/revisions.rb +1 -1
  153. data/lib/hexapdf/serializer.rb +2 -2
  154. data/lib/hexapdf/stream.rb +1 -1
  155. data/lib/hexapdf/task.rb +1 -1
  156. data/lib/hexapdf/task/dereference.rb +1 -1
  157. data/lib/hexapdf/task/optimize.rb +1 -1
  158. data/lib/hexapdf/tokenizer.rb +1 -1
  159. data/lib/hexapdf/type.rb +1 -1
  160. data/lib/hexapdf/type/acro_form.rb +7 -1
  161. data/lib/hexapdf/type/acro_form/appearance_generator.rb +401 -0
  162. data/lib/hexapdf/type/acro_form/button_field.rb +300 -0
  163. data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
  164. data/lib/hexapdf/type/acro_form/field.rb +220 -17
  165. data/lib/hexapdf/type/acro_form/form.rb +157 -7
  166. data/lib/hexapdf/type/acro_form/text_field.rb +186 -0
  167. data/lib/hexapdf/type/acro_form/variable_text_field.rb +122 -0
  168. data/lib/hexapdf/type/action.rb +1 -1
  169. data/lib/hexapdf/type/actions.rb +1 -1
  170. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  171. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  172. data/lib/hexapdf/type/actions/launch.rb +1 -1
  173. data/lib/hexapdf/type/actions/uri.rb +1 -1
  174. data/lib/hexapdf/type/annotation.rb +73 -3
  175. data/lib/hexapdf/type/annotations.rb +1 -1
  176. data/lib/hexapdf/type/annotations/link.rb +2 -2
  177. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  178. data/lib/hexapdf/type/annotations/text.rb +1 -1
  179. data/lib/hexapdf/type/annotations/widget.rb +239 -2
  180. data/lib/hexapdf/type/catalog.rb +21 -1
  181. data/lib/hexapdf/type/cid_font.rb +1 -1
  182. data/lib/hexapdf/type/embedded_file.rb +1 -1
  183. data/lib/hexapdf/type/file_specification.rb +1 -1
  184. data/lib/hexapdf/type/font.rb +18 -1
  185. data/lib/hexapdf/type/font_descriptor.rb +2 -2
  186. data/lib/hexapdf/type/font_simple.rb +1 -1
  187. data/lib/hexapdf/type/font_true_type.rb +1 -1
  188. data/lib/hexapdf/type/font_type0.rb +1 -1
  189. data/lib/hexapdf/type/font_type1.rb +16 -1
  190. data/lib/hexapdf/type/font_type3.rb +1 -1
  191. data/lib/hexapdf/type/form.rb +10 -1
  192. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  193. data/lib/hexapdf/type/icon_fit.rb +1 -1
  194. data/lib/hexapdf/type/image.rb +3 -1
  195. data/lib/hexapdf/type/info.rb +1 -1
  196. data/lib/hexapdf/type/names.rb +1 -1
  197. data/lib/hexapdf/type/object_stream.rb +1 -1
  198. data/lib/hexapdf/type/page.rb +20 -5
  199. data/lib/hexapdf/type/page_tree_node.rb +8 -11
  200. data/lib/hexapdf/type/resources.rb +16 -3
  201. data/lib/hexapdf/type/trailer.rb +2 -3
  202. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  203. data/lib/hexapdf/type/xref_stream.rb +1 -1
  204. data/lib/hexapdf/utils/bit_field.rb +38 -24
  205. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  206. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  207. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  208. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  209. data/lib/hexapdf/utils/object_hash.rb +1 -1
  210. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  211. data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
  212. data/lib/hexapdf/version.rb +2 -2
  213. data/lib/hexapdf/writer.rb +1 -1
  214. data/lib/hexapdf/xref_section.rb +1 -1
  215. data/test/hexapdf/content/common.rb +2 -2
  216. data/test/hexapdf/content/test_color_space.rb +71 -8
  217. data/test/hexapdf/content/test_operator.rb +22 -22
  218. data/test/hexapdf/content/test_parser.rb +14 -0
  219. data/test/hexapdf/document/test_fonts.rb +1 -1
  220. data/test/hexapdf/document/test_pages.rb +6 -6
  221. data/test/hexapdf/encryption/test_security_handler.rb +4 -0
  222. data/test/hexapdf/font/encoding/test_base.rb +10 -0
  223. data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
  224. data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
  225. data/test/hexapdf/font/test_type1_wrapper.rb +33 -8
  226. data/test/hexapdf/layout/test_style.rb +1 -1
  227. data/test/hexapdf/test_document.rb +12 -0
  228. data/test/hexapdf/test_parser.rb +10 -0
  229. data/test/hexapdf/test_rectangle.rb +14 -0
  230. data/test/hexapdf/test_revision.rb +3 -0
  231. data/test/hexapdf/test_serializer.rb +3 -3
  232. data/test/hexapdf/test_writer.rb +2 -2
  233. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +515 -0
  234. data/test/hexapdf/type/acro_form/test_button_field.rb +276 -0
  235. data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
  236. data/test/hexapdf/type/acro_form/test_field.rb +124 -6
  237. data/test/hexapdf/type/acro_form/test_form.rb +189 -22
  238. data/test/hexapdf/type/acro_form/test_text_field.rb +119 -0
  239. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
  240. data/test/hexapdf/type/annotations/test_text.rb +1 -1
  241. data/test/hexapdf/type/annotations/test_widget.rb +199 -0
  242. data/test/hexapdf/type/test_annotation.rb +45 -0
  243. data/test/hexapdf/type/test_catalog.rb +18 -0
  244. data/test/hexapdf/type/test_font.rb +5 -0
  245. data/test/hexapdf/type/test_font_type1.rb +8 -0
  246. data/test/hexapdf/type/test_form.rb +18 -0
  247. data/test/hexapdf/type/test_image.rb +7 -0
  248. data/test/hexapdf/type/test_page.rb +37 -6
  249. data/test/hexapdf/type/test_page_tree_node.rb +20 -12
  250. data/test/hexapdf/type/test_resources.rb +20 -0
  251. data/test/hexapdf/type/test_trailer.rb +4 -0
  252. data/test/hexapdf/utils/test_bit_field.rb +13 -1
  253. data/test/test_helper.rb +1 -1
  254. metadata +38 -18
  255. data/lib/hexapdf/filter/dct_decode.rb +0 -60
@@ -8,7 +8,7 @@ describe HexaPDF::Type::Annotations::Text do
8
8
  before do
9
9
  @doc = HexaPDF::Document.new
10
10
  @doc.version = '1.5'
11
- @annot = HexaPDF::Type::Annotations::Text.new({Rect: [0, 0, 1, 1]}, document: @doc)
11
+ @annot = HexaPDF::Type::Annotations::Text.new({Rect: [0, 0, 1, 1]}, document: @doc, oid: 1)
12
12
  end
13
13
 
14
14
  describe "validation" do
@@ -22,3 +22,202 @@ describe HexaPDF::Type::Annotations::Widget::AppearanceCharacteristics do
22
22
  end
23
23
  end
24
24
  end
25
+
26
+ describe HexaPDF::Type::Annotations::Widget do
27
+ before do
28
+ @doc = HexaPDF::Document.new
29
+ @widget = @doc.wrap({Type: :Annot, Subtype: :Widget})
30
+ end
31
+
32
+ describe "form_field" do
33
+ it "works for the field and widget being the same object" do
34
+ @widget[:FT] = :Tx
35
+ @widget[:T] = 'field'
36
+ result = @widget.form_field
37
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
38
+ assert_same(@widget.data, result.data)
39
+ end
40
+
41
+ it "works for a field with a parent field and the widget being the same object" do
42
+ @widget[:Parent] = {FT: :Tx, T: 'parent', Kids: [@widget]}
43
+ @widget[:T] = 'field'
44
+ result = @widget.form_field
45
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
46
+ assert_same(@widget.data, result.data)
47
+ end
48
+
49
+ it "works for the widget being in the /Kids array of the field" do
50
+ @widget[:Parent] = {FT: :Tx, T: 'parent', Kids: [@widget]}
51
+ result = @widget.form_field
52
+ assert_kind_of(HexaPDF::Type::AcroForm::TextField, result)
53
+ refute_same(@widget.data, result.data)
54
+ end
55
+ end
56
+
57
+ describe "background_color" do
58
+ it "returns the current background color" do
59
+ assert_nil(@widget.background_color)
60
+ @widget[:MK] = {BG: [1]}
61
+ assert_equal([1], @widget.background_color.components)
62
+ end
63
+
64
+ it "sets the color and returns self" do
65
+ assert_same(@widget, @widget.background_color(51))
66
+ assert_equal([0.2], @widget.background_color.components)
67
+ end
68
+ end
69
+
70
+ describe "border_style" do
71
+ before do
72
+ @widget[:MK] = {BC: [1, 0, 1]}
73
+ @color = HexaPDF::Content::ColorSpace.prenormalized_device_color([1, 0, 1])
74
+ end
75
+
76
+ describe "getter" do
77
+ it "no /Border, /BS or /MK set" do
78
+ @widget.delete(:MK)
79
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
80
+ end
81
+
82
+ it "no /Border, /BS but with /MK empty" do
83
+ @widget[:MK].delete(:BC)
84
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
85
+ end
86
+
87
+ it "uses the color from /MK" do
88
+ assert_equal([1, @color, :solid, 0, 0], @widget.border_style.to_a)
89
+ @widget[:MK][:BC] = []
90
+ assert_equal([1, nil, :solid, 0, 0], @widget.border_style.to_a)
91
+ end
92
+
93
+ it "uses the data from /Border" do
94
+ @widget[:Border] = [1, 2, 3, [1, 2]]
95
+ assert_equal([3, @color, [1, 2], 1, 2], @widget.border_style.to_a)
96
+ end
97
+
98
+ it "uses the data from /BS, overriding /Border values" do
99
+ @widget[:Border] = [1, 2, 3, [1, 2]]
100
+ @widget[:BS] = {W: 5, S: :D, D: [5, 6]}
101
+ assert_equal([5, @color, [5, 6], 0, 0], @widget.border_style.to_a)
102
+
103
+ [[:S, :solid], [:D, [5, 6]], [:B, :beveled], [:I, :inset],
104
+ [:U, :underlined], [:Unknown, :solid]].each do |val, result|
105
+ @widget[:BS] = {S: val, D: [5, 6]}
106
+ assert_equal([1, @color, result, 0, 0], @widget.border_style.to_a)
107
+ end
108
+ end
109
+ end
110
+
111
+ describe "setter" do
112
+ it "returns self" do
113
+ assert_equal(@widget, @widget.border_style(width: 1))
114
+ end
115
+
116
+ it "sets the color" do
117
+ @widget.border_style(color: [1.0, 51, 1.0])
118
+ assert_equal([1, 0.2, 1], @widget[:MK][:BC].value)
119
+
120
+ @widget.border_style(color: :transparent)
121
+ assert_equal([], @widget[:MK][:BC].value)
122
+ end
123
+
124
+ it "sets the width" do
125
+ @widget.border_style(width: 2)
126
+ assert_equal(2, @widget[:BS][:W])
127
+ end
128
+
129
+ it "sets the style" do
130
+ [[:solid, :S], [[5, 6], :D], [:beveled, :B], [:inset, :I], [:underlined, :U]].each do |val, r|
131
+ @widget.border_style(style: val)
132
+ assert_equal(r, @widget[:BS][:S])
133
+ assert_equal(val, @widget[:BS][:D].value) if r == :D
134
+ end
135
+ end
136
+
137
+ it "overrides all priorly set values" do
138
+ @widget.border_style(width: 3, style: :inset, color: [1])
139
+ @widget.border_style(width: 5)
140
+ border_style = @widget.border_style
141
+ assert_equal(:solid, border_style.style)
142
+ assert_equal([0], border_style.color.components)
143
+ end
144
+
145
+ it "raises an error for an unknown style" do
146
+ assert_raises(ArgumentError) { @widget.border_style(style: :unknown) }
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "marker_style" do
152
+ before do
153
+ @chars = %w[4 l 8 u n H S]
154
+ @values = [:check, :circle, :cross, :diamond, :square, :star, 'S']
155
+ @widget[:Parent] = {FT: :Btn}
156
+ end
157
+
158
+ describe "style" do
159
+ it "returns the style" do
160
+ @chars.zip(@values) do |char, result|
161
+ @widget[:MK] = {CA: char}
162
+ assert_equal(result, @widget.marker_style.style)
163
+ end
164
+ end
165
+
166
+ it "returns the correct default button style depending on the field" do
167
+ @widget.form_field.initialize_as_check_box
168
+ assert_equal(:check, @widget.marker_style.style)
169
+ @widget.form_field.initialize_as_radio_button
170
+ assert_equal(:circle, @widget.marker_style.style)
171
+ end
172
+
173
+ it "sets the button style" do
174
+ @values.zip(@chars) do |argument, char|
175
+ @widget.marker_style(style: argument)
176
+ assert_equal(char, @widget[:MK][:CA])
177
+ end
178
+ end
179
+
180
+ it "fails if an invalid argument is provided" do
181
+ assert_raises(ArgumentError) { @widget.marker_style(style: 5) }
182
+ end
183
+ end
184
+
185
+ describe "size" do
186
+ it "returns the size" do
187
+ @widget.form_field[:DA] = "/F 15 Tf"
188
+ assert_equal(15, @widget.marker_style.size)
189
+ @widget[:DA] = "/F 10 Tf"
190
+ assert_equal(10, @widget.marker_style.size)
191
+ end
192
+
193
+ it "returns the default size if none is set" do
194
+ assert_equal(0, @widget.marker_style.size)
195
+ end
196
+
197
+ it "sets the given size" do
198
+ @widget.marker_style(size: 10)
199
+ assert_equal('/ZaDb 10 Tf 0.0 g', @widget[:DA])
200
+ end
201
+ end
202
+
203
+ describe "color" do
204
+ it "returns the color" do
205
+ @widget.form_field[:DA] = "0 1 0 rg"
206
+ assert_equal([0, 1, 0], @widget.marker_style.color.components)
207
+ @widget[:DA] = "0 0 1 rg"
208
+ assert_equal([0, 0, 1], @widget.marker_style.color.components)
209
+ end
210
+
211
+ it "returns the default color if none is set" do
212
+ assert_equal([0], @widget.marker_style.color.components)
213
+ end
214
+
215
+ it "sets the given color" do
216
+ @widget.marker_style(color: [1.0, 51, 1.0])
217
+ assert_equal([1, 0.2, 1], @widget.marker_style.color.components)
218
+ @widget.marker_style(color: [1.0, 20, 1.0, 1.0])
219
+ assert_equal([1, 0.2, 1, 1], @widget.marker_style.color.components)
220
+ end
221
+ end
222
+ end
223
+ end
@@ -4,12 +4,57 @@ require 'test_helper'
4
4
  require 'hexapdf/document'
5
5
  require 'hexapdf/type/annotation'
6
6
 
7
+ describe HexaPDF::Type::Annotation::AppearanceDictionary do
8
+ before do
9
+ @doc = HexaPDF::Document.new
10
+ @ap = @doc.add({N: :n, D: :d, R: :r}, type: :XXAppearanceDictionary)
11
+ end
12
+
13
+ it "resolves the normal appearance" do
14
+ assert_equal(:n, @ap.normal_appearance)
15
+ end
16
+
17
+ it "resolves the rollover appearance" do
18
+ assert_equal(:r, @ap.rollover_appearance)
19
+ @ap.delete(:R)
20
+ assert_equal(:n, @ap.rollover_appearance)
21
+ end
22
+
23
+ it "resolves the down appearance" do
24
+ assert_equal(:d, @ap.down_appearance)
25
+ @ap.delete(:D)
26
+ assert_equal(:n, @ap.down_appearance)
27
+ end
28
+ end
29
+
7
30
  describe HexaPDF::Type::Annotation do
8
31
  before do
9
32
  @doc = HexaPDF::Document.new
10
33
  @annot = @doc.add({Type: :Annot, F: 0b100011})
11
34
  end
12
35
 
36
+ it "must always be indirect" do
37
+ @annot.must_be_indirect = false
38
+ assert(@annot.must_be_indirect?)
39
+ end
40
+
41
+ it "returns the appearance dictionary" do
42
+ @annot[:AP] = :yes
43
+ assert_equal(:yes, @annot.appearance)
44
+ end
45
+
46
+ it "checks whether an appearance exists" do
47
+ refute(@annot.appearance?)
48
+ @annot[:AP] = {N: {}}
49
+ refute(@annot.appearance?)
50
+ @annot[:AP][:N] = @doc.wrap({}, stream: '')
51
+ assert(@annot.appearance?)
52
+ @annot[:AP][:N] = {okay: @doc.wrap({}, stream: '')}
53
+ assert(@annot.appearance?)
54
+ @annot[:AP][:N][:Off] = :other
55
+ refute(@annot.appearance?)
56
+ end
57
+
13
58
  describe "flags" do
14
59
  it "returns all flags" do
15
60
  assert_equal([:invisible, :hidden, :no_view], @annot.flags)
@@ -21,6 +21,24 @@ describe HexaPDF::Type::Catalog do
21
21
  assert_equal(:Pages, pages.type)
22
22
  end
23
23
 
24
+ describe "acro_form" do
25
+ it "returns an existing form object" do
26
+ @catalog[:AcroForm] = :test
27
+ assert_equal(:test, @catalog.acro_form)
28
+ end
29
+
30
+ it "returns an existing form object even if create: true" do
31
+ @catalog[:AcroForm] = :test
32
+ assert_equal(:test, @catalog.acro_form(create: true))
33
+ end
34
+
35
+ it "creates a new AcroForm object with defaults if create: true" do
36
+ form = @catalog.acro_form(create: true)
37
+ assert_kind_of(HexaPDF::Type::AcroForm::Form, form)
38
+ assert(form[:DA])
39
+ end
40
+ end
41
+
24
42
  describe "validation" do
25
43
  it "creates the page tree if necessary" do
26
44
  refute(@catalog.validate(auto_correct: false))
@@ -17,6 +17,11 @@ describe HexaPDF::Type::Font do
17
17
  @font = @doc.add({Type: :Font, BaseFont: :TestFont, FontDescriptor: fd, ToUnicode: cmap})
18
18
  end
19
19
 
20
+ it "allows setting and returning a font wrapper object" do
21
+ @font.font_wrapper = :fake_wrapper
22
+ assert_equal(:fake_wrapper, @font.font_wrapper)
23
+ end
24
+
20
25
  it "must always be an indirect" do
21
26
  assert(@font.must_be_indirect?)
22
27
  end
@@ -57,6 +57,14 @@ describe HexaPDF::Type::FontType1 do
57
57
  FirstChar: 32, LastChar: 34, Widths: [600, 0, 700]})
58
58
  end
59
59
 
60
+ it "can create a usable font wrapper for the standard fonts" do
61
+ wrapper = @font.font_wrapper
62
+ assert(wrapper)
63
+ assert_same(@font, wrapper.pdf_object)
64
+ assert_equal(@font[:BaseFont], wrapper.wrapped_font.font_name.intern)
65
+ assert_same(wrapper, @font.font_wrapper)
66
+ end
67
+
60
68
  describe "encoding" do
61
69
  it "returns the the standard font's encoding" do
62
70
  @font.delete(:Encoding)
@@ -82,9 +82,27 @@ describe HexaPDF::Type::Form do
82
82
  end
83
83
 
84
84
  describe "canvas" do
85
+ # Asserts that the form's contents contains the operators.
86
+ def assert_operators(form, operators)
87
+ processor = TestHelper::OperatorRecorder.new
88
+ form.process_contents(processor)
89
+ assert_equal(operators, processor.recorded_ops)
90
+ end
91
+
85
92
  it "always returns the same Canvas instance" do
93
+ @form[:BBox] = [0, 0, 100, 100]
86
94
  canvas = @form.canvas
87
95
  assert_same(canvas, @form.canvas)
96
+ assert_operators(@form, [])
97
+ end
98
+
99
+ it "always moves the origin to the bottom left corner of the bounding box" do
100
+ @form[:BBox] = [-10, -5, 100, 300]
101
+ @form.canvas.line_width = 5
102
+ assert_operators(@form, [[:save_graphics_state],
103
+ [:concatenate_matrix, [1, 0, 0, 1, -10, -5]],
104
+ [:set_line_width, [5]],
105
+ [:restore_graphics_state]])
88
106
  end
89
107
 
90
108
  it "fails if the form XObject already has data" do
@@ -120,6 +120,12 @@ describe HexaPDF::Type::Image do
120
120
  assert_equal(:other, info.color_space)
121
121
  assert_equal(-1, info.components)
122
122
  end
123
+
124
+ it "processes the SMask entry" do
125
+ @image[:SMask] = :something
126
+ info = @image.info
127
+ refute(info.writable)
128
+ end
123
129
  end
124
130
 
125
131
  describe "write" do
@@ -182,6 +188,7 @@ describe HexaPDF::Type::Image do
182
188
  end
183
189
 
184
190
  Dir.glob(File.join(TEST_DATA_DIR, 'images', '*.png')).each do |png_file|
191
+ next if png_file =~ /alpha/
185
192
  it "writes #{File.basename(png_file)} correctly as PNG file" do
186
193
  image = @doc.images.add(png_file)
187
194
  if png_file =~ /greyscale-1bit.png/ # force use of arrays for one image
@@ -331,31 +331,36 @@ describe HexaPDF::Type::Page do
331
331
  @page.canvas(type: :overlay).line_width = 5
332
332
  assert_operators(@page, [[:save_graphics_state], [:restore_graphics_state],
333
333
  [:save_graphics_state], [:set_line_width, [10]],
334
- [:restore_graphics_state], [:set_line_width, [5]]])
334
+ [:restore_graphics_state], [:save_graphics_state],
335
+ [:set_line_width, [5]], [:restore_graphics_state]])
335
336
 
336
337
  @page.canvas(type: :underlay).line_width = 2
337
338
  assert_operators(@page, [[:save_graphics_state], [:set_line_width, [2]],
338
339
  [:restore_graphics_state], [:save_graphics_state],
339
340
  [:set_line_width, [10]],
340
- [:restore_graphics_state], [:set_line_width, [5]]])
341
+ [:restore_graphics_state], [:save_graphics_state],
342
+ [:set_line_width, [5]], [:restore_graphics_state]])
341
343
  end
342
344
 
343
345
  it "works correctly if invoked on an empty page, using type :underlay in first invocation" do
344
346
  @page.canvas(type: :underlay).line_width = 2
345
347
  assert_operators(@page, [[:save_graphics_state], [:set_line_width, [2]],
348
+ [:restore_graphics_state], [:save_graphics_state],
346
349
  [:restore_graphics_state], [:save_graphics_state],
347
350
  [:restore_graphics_state]])
348
351
 
349
352
  @page.canvas.line_width = 10
350
353
  assert_operators(@page, [[:save_graphics_state], [:set_line_width, [2]],
351
354
  [:restore_graphics_state], [:save_graphics_state],
352
- [:set_line_width, [10]], [:restore_graphics_state]])
355
+ [:set_line_width, [10]], [:restore_graphics_state],
356
+ [:save_graphics_state], [:restore_graphics_state]])
353
357
 
354
358
  @page.canvas(type: :overlay).line_width = 5
355
359
  assert_operators(@page, [[:save_graphics_state], [:set_line_width, [2]],
356
360
  [:restore_graphics_state], [:save_graphics_state],
357
361
  [:set_line_width, [10]],
358
- [:restore_graphics_state], [:set_line_width, [5]]])
362
+ [:restore_graphics_state], [:save_graphics_state],
363
+ [:set_line_width, [5]], [:restore_graphics_state]])
359
364
  end
360
365
 
361
366
  it "works correctly if invoked on a page with existing contents" do
@@ -364,13 +369,39 @@ describe HexaPDF::Type::Page do
364
369
  @page.canvas(type: :overlay).line_width = 5
365
370
  assert_operators(@page, [[:save_graphics_state], [:restore_graphics_state],
366
371
  [:save_graphics_state], [:set_line_width, [10]],
367
- [:restore_graphics_state], [:set_line_width, [5]]])
372
+ [:restore_graphics_state],
373
+ [:save_graphics_state], [:set_line_width, [5]],
374
+ [:restore_graphics_state]])
368
375
 
369
376
  @page.canvas(type: :underlay).line_width = 2
370
377
  assert_operators(@page, [[:save_graphics_state], [:set_line_width, [2]],
371
378
  [:restore_graphics_state], [:save_graphics_state],
372
379
  [:set_line_width, [10]],
373
- [:restore_graphics_state], [:set_line_width, [5]]])
380
+ [:restore_graphics_state],
381
+ [:save_graphics_state], [:set_line_width, [5]],
382
+ [:restore_graphics_state]])
383
+ end
384
+
385
+ it "works correctly if the page has its origin not at (0,0)" do
386
+ @page.box(:media, [-10, -5, 100, 300])
387
+ @page.canvas(type: :underlay).line_width = 2
388
+ @page.canvas(type: :page).line_width = 2
389
+ @page.canvas(type: :overlay).line_width = 2
390
+
391
+ assert_operators(@page, [[:save_graphics_state],
392
+ [:concatenate_matrix, [1, 0, 0, 1, -10, -5]],
393
+ [:set_line_width, [2]],
394
+ [:restore_graphics_state],
395
+
396
+ [:save_graphics_state],
397
+ [:concatenate_matrix, [1, 0, 0, 1, -10, -5]],
398
+ [:set_line_width, [2]],
399
+ [:restore_graphics_state],
400
+
401
+ [:save_graphics_state],
402
+ [:concatenate_matrix, [1, 0, 0, 1, -10, -5]],
403
+ [:set_line_width, [2]],
404
+ [:restore_graphics_state]])
374
405
  end
375
406
 
376
407
  it "fails if the page canvas is requested for a page with existing contents" do