hexapdf 0.11.9 → 0.13.0

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -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 +22 -11
  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 +3 -2
  30. data/lib/hexapdf/cli/images.rb +1 -1
  31. data/lib/hexapdf/cli/info.rb +52 -3
  32. data/lib/hexapdf/cli/inspect.rb +31 -9
  33. data/lib/hexapdf/cli/merge.rb +2 -2
  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 +81 -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 +4 -4
  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 +5 -5
  55. data/lib/hexapdf/dictionary_fields.rb +2 -10
  56. data/lib/hexapdf/document.rb +45 -17
  57. data/lib/hexapdf/document/files.rb +1 -2
  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 +2 -2
  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 +2 -1
  70. data/lib/hexapdf/encryption/standard_security_handler.rb +2 -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 +2 -5
  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 +2 -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 +3 -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 +4 -3
  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 +2 -2
  137. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  138. data/lib/hexapdf/layout/style.rb +24 -24
  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 +4 -3
  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 +32 -27
  147. data/lib/hexapdf/parser.rb +69 -6
  148. data/lib/hexapdf/pdf_array.rb +10 -3
  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 +30 -22
  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 +7 -5
  158. data/lib/hexapdf/tokenizer.rb +5 -4
  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 +405 -0
  162. data/lib/hexapdf/type/acro_form/button_field.rb +305 -0
  163. data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
  164. data/lib/hexapdf/type/acro_form/field.rb +250 -17
  165. data/lib/hexapdf/type/acro_form/form.rb +159 -7
  166. data/lib/hexapdf/type/acro_form/text_field.rb +187 -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 +4 -3
  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 +238 -2
  180. data/lib/hexapdf/type/catalog.rb +23 -3
  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 +2 -2
  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 +4 -2
  187. data/lib/hexapdf/type/font_true_type.rb +7 -3
  188. data/lib/hexapdf/type/font_type0.rb +2 -2
  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 +12 -2
  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 +5 -3
  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 +36 -12
  199. data/lib/hexapdf/type/page_tree_node.rb +37 -16
  200. data/lib/hexapdf/type/resources.rb +17 -3
  201. data/lib/hexapdf/type/trailer.rb +4 -6
  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 +19 -16
  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/common_tokenizer_tests.rb +6 -1
  216. data/test/hexapdf/content/common.rb +2 -2
  217. data/test/hexapdf/content/graphic_object/test_arc.rb +4 -4
  218. data/test/hexapdf/content/test_canvas.rb +3 -3
  219. data/test/hexapdf/content/test_color_space.rb +71 -8
  220. data/test/hexapdf/content/test_operator.rb +22 -22
  221. data/test/hexapdf/content/test_parser.rb +14 -0
  222. data/test/hexapdf/document/test_fonts.rb +1 -1
  223. data/test/hexapdf/document/test_pages.rb +6 -6
  224. data/test/hexapdf/encryption/test_aes.rb +4 -4
  225. data/test/hexapdf/encryption/test_standard_security_handler.rb +11 -11
  226. data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
  227. data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
  228. data/test/hexapdf/font/encoding/test_base.rb +10 -0
  229. data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
  230. data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
  231. data/test/hexapdf/font/test_type1_wrapper.rb +33 -8
  232. data/test/hexapdf/layout/test_style.rb +1 -1
  233. data/test/hexapdf/layout/test_text_layouter.rb +3 -4
  234. data/test/hexapdf/test_configuration.rb +2 -2
  235. data/test/hexapdf/test_dictionary.rb +3 -1
  236. data/test/hexapdf/test_dictionary_fields.rb +2 -2
  237. data/test/hexapdf/test_document.rb +16 -4
  238. data/test/hexapdf/test_object.rb +44 -26
  239. data/test/hexapdf/test_parser.rb +125 -55
  240. data/test/hexapdf/test_pdf_array.rb +7 -0
  241. data/test/hexapdf/test_rectangle.rb +14 -0
  242. data/test/hexapdf/test_revision.rb +3 -0
  243. data/test/hexapdf/test_revisions.rb +35 -0
  244. data/test/hexapdf/test_writer.rb +2 -2
  245. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +521 -0
  246. data/test/hexapdf/type/acro_form/test_button_field.rb +281 -0
  247. data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
  248. data/test/hexapdf/type/acro_form/test_field.rb +163 -6
  249. data/test/hexapdf/type/acro_form/test_form.rb +189 -22
  250. data/test/hexapdf/type/acro_form/test_text_field.rb +121 -0
  251. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
  252. data/test/hexapdf/type/annotations/test_text.rb +1 -1
  253. data/test/hexapdf/type/annotations/test_widget.rb +199 -0
  254. data/test/hexapdf/type/test_annotation.rb +45 -0
  255. data/test/hexapdf/type/test_catalog.rb +18 -0
  256. data/test/hexapdf/type/test_font.rb +5 -0
  257. data/test/hexapdf/type/test_font_simple.rb +2 -1
  258. data/test/hexapdf/type/test_font_true_type.rb +6 -0
  259. data/test/hexapdf/type/test_font_type1.rb +8 -0
  260. data/test/hexapdf/type/test_form.rb +19 -1
  261. data/test/hexapdf/type/test_image.rb +7 -0
  262. data/test/hexapdf/type/test_page.rb +45 -7
  263. data/test/hexapdf/type/test_page_tree_node.rb +62 -12
  264. data/test/hexapdf/type/test_resources.rb +20 -0
  265. data/test/hexapdf/type/test_trailer.rb +4 -0
  266. data/test/hexapdf/utils/test_bit_field.rb +15 -1
  267. data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -9
  268. data/test/test_helper.rb +1 -1
  269. metadata +34 -21
  270. data/lib/hexapdf/filter/dct_decode.rb +0 -60
@@ -254,89 +254,89 @@ end
254
254
 
255
255
  describe_operator :SetStrokingColor, :SC do
256
256
  it "sets the stroking color" do
257
- invoke(128)
258
- assert_equal(@processor.resources.color_space(:DeviceGray).color(128),
257
+ invoke(0.2)
258
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
259
259
  @processor.graphics_state.stroke_color)
260
260
  end
261
261
 
262
262
  it "serializes correctly" do
263
- assert_serialized(128, 129, 130)
263
+ assert_serialized(0.2, 0.5, 0.8)
264
264
  end
265
265
  end
266
266
 
267
267
  describe_operator :SetNonStrokingColor, :sc do
268
268
  it "sets the non stroking color" do
269
- invoke(128)
270
- assert_equal(@processor.resources.color_space(:DeviceGray).color(128),
269
+ invoke(0.2)
270
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
271
271
  @processor.graphics_state.fill_color)
272
272
  end
273
273
 
274
274
  it "serializes correctly" do
275
- assert_serialized(128, 129, 130)
275
+ assert_serialized(0.2, 0.5, 0.8)
276
276
  end
277
277
  end
278
278
 
279
279
  describe_operator :SetDeviceGrayStrokingColor, :G do
280
280
  it "sets the DeviceGray stroking color" do
281
- invoke(128)
282
- assert_equal(@processor.resources.color_space(:DeviceGray).color(128),
281
+ invoke(0.2)
282
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
283
283
  @processor.graphics_state.stroke_color)
284
284
  end
285
285
  end
286
286
 
287
287
  describe_operator :SetDeviceGrayNonStrokingColor, :g do
288
288
  it "sets the DeviceGray non stroking color" do
289
- invoke(128)
290
- assert_equal(@processor.resources.color_space(:DeviceGray).color(128),
289
+ invoke(0.2)
290
+ assert_equal(@processor.resources.color_space(:DeviceGray).color(51),
291
291
  @processor.graphics_state.fill_color)
292
292
  end
293
293
  end
294
294
 
295
295
  describe_operator :SetDeviceRGBStrokingColor, :RG do
296
296
  it "sets the DeviceRGB stroking color" do
297
- invoke(128, 0, 128)
298
- assert_equal(@processor.resources.color_space(:DeviceRGB).color(128, 0, 128),
297
+ invoke(0.2, 0, 0.2)
298
+ assert_equal(@processor.resources.color_space(:DeviceRGB).color(51, 0, 51),
299
299
  @processor.graphics_state.stroke_color)
300
300
  end
301
301
 
302
302
  it "serializes correctly" do
303
- assert_serialized(128, 129, 130)
303
+ assert_serialized(0.2, 0.3, 0.4)
304
304
  end
305
305
  end
306
306
 
307
307
  describe_operator :SetDeviceRGBNonStrokingColor, :rg do
308
308
  it "sets the DeviceRGB non stroking color" do
309
- invoke(128, 0, 128)
310
- assert_equal(@processor.resources.color_space(:DeviceRGB).color(128, 0, 128),
309
+ invoke(0.2, 0, 0.2)
310
+ assert_equal(@processor.resources.color_space(:DeviceRGB).color(51, 0, 51),
311
311
  @processor.graphics_state.fill_color)
312
312
  end
313
313
 
314
314
  it "serializes correctly" do
315
- assert_serialized(128, 129, 130)
315
+ assert_serialized(0.2, 0.3, 0.4)
316
316
  end
317
317
  end
318
318
 
319
319
  describe_operator :SetDeviceCMYKStrokingColor, :K do
320
320
  it "sets the DeviceCMYK stroking color" do
321
- invoke(128, 0, 128, 128)
322
- assert_equal(@processor.resources.color_space(:DeviceCMYK).color(128, 0, 128, 128),
321
+ invoke(0.51, 0, 0.51, 0.51)
322
+ assert_equal(@processor.resources.color_space(:DeviceCMYK).color(51, 0, 51, 51),
323
323
  @processor.graphics_state.stroke_color)
324
324
  end
325
325
 
326
326
  it "serializes correctly" do
327
- assert_serialized(128, 129, 130, 131)
327
+ assert_serialized(0.2, 0.3, 0.4, 0.5)
328
328
  end
329
329
  end
330
330
 
331
331
  describe_operator :SetDeviceCMYKNonStrokingColor, :k do
332
332
  it "sets the DeviceCMYK non stroking color" do
333
- invoke(128, 0, 128, 128)
334
- assert_equal(@processor.resources.color_space(:DeviceCMYK).color(128, 0, 128, 128),
333
+ invoke(0.51, 0, 0.51, 0.51)
334
+ assert_equal(@processor.resources.color_space(:DeviceCMYK).color(51, 0, 51, 51),
335
335
  @processor.graphics_state.fill_color)
336
336
  end
337
337
 
338
338
  it "serializes correctly" do
339
- assert_serialized(128, 129, 130, 131)
339
+ assert_serialized(0.2, 0.3, 0.4, 0.5)
340
340
  end
341
341
  end
342
342
 
@@ -81,5 +81,19 @@ describe HexaPDF::Content::Parser do
81
81
  end
82
82
  assert_match(/EI not found/, exp.message)
83
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
84
98
  end
85
99
  end
@@ -36,7 +36,7 @@ describe HexaPDF::Document::Fonts do
36
36
  assert_same(font, @doc.fonts.add(:TestFont, variant: :none))
37
37
  end
38
38
 
39
- it "fails if the requested font is not found" do
39
+ it "fails if the requested font is not found" do
40
40
  @doc.config['font_loader'] << 'HexaPDF::FontLoader::Standard14'
41
41
  error = assert_raises(HexaPDF::Error) { @doc.fonts.add("Unknown") }
42
42
  assert_match(/Times \(none/, error.message)
@@ -74,20 +74,20 @@ describe HexaPDF::Document::Pages do
74
74
 
75
75
  describe "delete" do
76
76
  it "deletes a given page" do
77
- page = @doc.pages.add
78
- @doc.pages.add
77
+ page1 = @doc.pages.add
78
+ page2 = @doc.pages.add
79
79
 
80
- assert_same(page, @doc.pages.delete(page))
81
- assert_nil(@doc.pages.delete(page))
80
+ @doc.pages.delete(page1)
81
+ assert_equal([page2], @doc.pages.root[:Kids].value)
82
82
  end
83
83
  end
84
84
 
85
85
  describe "delete_at" do
86
86
  it "deletes a page at a given index" do
87
87
  page1 = @doc.pages.add
88
- page2 = @doc.pages.add
88
+ @doc.pages.add
89
89
  page3 = @doc.pages.add
90
- assert_same(page2, @doc.pages.delete_at(1))
90
+ @doc.pages.delete_at(1)
91
91
  assert_equal([page1, page3], @doc.pages.root[:Kids].value)
92
92
  end
93
93
  end
@@ -101,13 +101,13 @@ describe HexaPDF::Encryption::AES do
101
101
  result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
102
102
  assert_equal('a' * 16, result)
103
103
 
104
- f = Fiber.new { 'a' * 31 + "\x00" }
104
+ f = Fiber.new { 'a' * 31 << "\x00" }
105
105
  result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
106
- assert_equal('a' * 15 + "\x00", result)
106
+ assert_equal('a' * 15 << "\x00", result)
107
107
 
108
- f = Fiber.new { 'a' * 29 + "\x00\x01\x03" }
108
+ f = Fiber.new { 'a' * 29 << "\x00\x01\x03" }
109
109
  result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
110
- assert_equal('a' * 13 + "\x00\x01\x03", result)
110
+ assert_equal('a' * 13 << "\x00\x01\x03", result)
111
111
  end
112
112
 
113
113
  it "fails on decryption if not enough bytes are provided" do
@@ -53,24 +53,24 @@ describe HexaPDF::Encryption::StandardEncryptionDictionary do
53
53
  end
54
54
 
55
55
  describe HexaPDF::Encryption::StandardSecurityHandler do
56
- TEST_FILES = Dir[File.join(TEST_DATA_DIR, 'standard-security-handler', '*.pdf')].sort
57
- USER_PASSWORD = 'uhexapdf'
58
- OWNER_PASSWORD = 'ohexapdf'
56
+ test_files = Dir[File.join(TEST_DATA_DIR, 'standard-security-handler', '*.pdf')].sort
57
+ user_password = 'uhexapdf'
58
+ owner_password = 'ohexapdf'
59
59
 
60
- MINIMAL_DOC = HexaPDF::Document.new(io: StringIO.new(MINIMAL_PDF))
60
+ minimal_doc = HexaPDF::Document.new(io: StringIO.new(MINIMAL_PDF))
61
61
 
62
- TEST_FILES.each do |file|
62
+ test_files.each do |file|
63
63
  basename = File.basename(file)
64
64
  it "can decrypt, encrypt and decrypt the encrypted file #{basename} with the user password" do
65
65
  begin
66
66
  doc = HexaPDF::Document.new(io: StringIO.new(File.binread(file)),
67
- decryption_opts: {password: USER_PASSWORD})
68
- assert_equal(MINIMAL_DOC.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
67
+ decryption_opts: {password: user_password})
68
+ assert_equal(minimal_doc.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
69
69
 
70
70
  out = StringIO.new(''.b)
71
71
  HexaPDF::Writer.new(doc, out).write
72
- doc = HexaPDF::Document.new(io: out, decryption_opts: {password: USER_PASSWORD})
73
- assert_equal(MINIMAL_DOC.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
72
+ doc = HexaPDF::Document.new(io: out, decryption_opts: {password: user_password})
73
+ assert_equal(minimal_doc.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
74
74
  rescue HexaPDF::EncryptionError => e
75
75
  flunk("Error processing #{basename}: #{e}")
76
76
  end
@@ -80,8 +80,8 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
80
80
  it "can decrypt the encrypted file #{basename} with the owner password" do
81
81
  begin
82
82
  doc = HexaPDF::Document.new(io: StringIO.new(File.binread(file)),
83
- decryption_opts: {password: OWNER_PASSWORD})
84
- assert_equal(MINIMAL_DOC.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
83
+ decryption_opts: {password: owner_password})
84
+ assert_equal(minimal_doc.trailer[:Info][:ModDate], doc.trailer[:Info][:ModDate])
85
85
  rescue HexaPDF::EncryptionError => e
86
86
  flunk("Error processing #{basename}: #{e}")
87
87
  end
@@ -33,7 +33,7 @@ describe HexaPDF::Filter::ASCII85Decode do
33
33
  end
34
34
 
35
35
  it "ignores data after the EOD marker" do
36
- assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded.dup + "~>abcdefg"))))
36
+ assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded << "~>abcdefg"))))
37
37
  end
38
38
 
39
39
  it "fails if the input contains invalid characters" do
@@ -24,7 +24,7 @@ describe HexaPDF::Filter::ASCIIHexDecode do
24
24
  end
25
25
 
26
26
  it "ignores data after the EOD marker" do
27
- assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded + '4e6f7gzz'))))
27
+ assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded << '4e6f7gzz'))))
28
28
  end
29
29
 
30
30
  it "assumes the missing char is '0' if the input length is odd" do
@@ -32,4 +32,14 @@ describe HexaPDF::Font::Encoding::Base do
32
32
  assert_nil(@base.unicode(66))
33
33
  end
34
34
  end
35
+
36
+ describe "code" do
37
+ it "returns the code for an existing glyph name" do
38
+ assert_equal(65, @base.code(:A))
39
+ end
40
+
41
+ it "returns nil if the glyph name is not referenced" do
42
+ assert_nil(@base.code(:Unknown))
43
+ end
44
+ end
35
45
  end
@@ -18,4 +18,12 @@ describe HexaPDF::Font::Encoding::DifferenceEncoding do
18
18
  assert_equal(:B, @enc.name(66))
19
19
  end
20
20
  end
21
+
22
+ describe "code" do
23
+ it "takes the encoding differences into account" do
24
+ assert_equal(65, @enc.code(:A))
25
+ @enc.code_to_name[65] = :Known
26
+ assert_equal(65, @enc.code(:Known))
27
+ end
28
+ end
21
29
  end
@@ -94,7 +94,10 @@ describe HexaPDF::Font::TrueTypeWrapper do
94
94
  @font_wrapper.encode(glyph)
95
95
  @doc.dispatch_message(:complete_objects)
96
96
 
97
- dict = @font_wrapper.dict
97
+ dict = @font_wrapper.pdf_object
98
+
99
+ # Checking the circular reference
100
+ assert_same(@font_wrapper, dict.font_wrapper)
98
101
 
99
102
  # Checking Type 0 font dictionary
100
103
  assert_equal(:Font, dict[:Type])
@@ -129,7 +132,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
129
132
  @font[:'OS/2'].typo_ascender = 1000
130
133
  font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font)
131
134
  font_wrapper.encode(glyph)
132
- fd = font_wrapper.dict[:DescendantFonts][0][:FontDescriptor]
135
+ fd = font_wrapper.pdf_object[:DescendantFonts][0][:FontDescriptor]
133
136
  assert_equal(800, fd[:CapHeight])
134
137
  assert_equal(500, fd[:XHeight])
135
138
  end
@@ -139,7 +142,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
139
142
  @font[:'OS/2'].cap_height = 1000 * @font[:head].units_per_em / 1000
140
143
  font_wrapper = HexaPDF::Font::TrueTypeWrapper.new(@doc, @font)
141
144
  font_wrapper.encode(glyph)
142
- fd = font_wrapper.dict[:DescendantFonts][0][:FontDescriptor]
145
+ fd = font_wrapper.pdf_object[:DescendantFonts][0][:FontDescriptor]
143
146
  assert_equal(1000, fd[:CapHeight])
144
147
  assert_equal(500, fd[:XHeight])
145
148
  end
@@ -151,7 +154,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
151
154
  @font_wrapper.encode(glyph)
152
155
  @doc.dispatch_message(:complete_objects)
153
156
 
154
- dict = @font_wrapper.dict
157
+ dict = @font_wrapper.pdf_object
155
158
 
156
159
  assert_equal(HexaPDF::Font::CMap.create_to_unicode_cmap([[3, ' '.ord], [glyph.id, 'H'.ord]]),
157
160
  dict[:ToUnicode].stream)
@@ -164,7 +167,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
164
167
  @font_wrapper.encode(@font_wrapper.glyph(10))
165
168
  @doc.dispatch_message(:complete_objects)
166
169
 
167
- font_data = @font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream
170
+ font_data = @font_wrapper.pdf_object[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream
168
171
  font = HexaPDF::Font::TrueType::Font.new(StringIO.new(font_data))
169
172
  assert_equal(@font[:glyf][0].raw_data, font[:glyf][0].raw_data)
170
173
  assert_equal(@font[:glyf][10].raw_data, font[:glyf][1].raw_data)
@@ -175,9 +178,9 @@ describe HexaPDF::Font::TrueTypeWrapper do
175
178
  @doc.dispatch_message(:complete_objects)
176
179
 
177
180
  assert_equal(File.size(@font_file),
178
- @font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2][:Length1])
181
+ @font_wrapper.pdf_object[:DescendantFonts][0][:FontDescriptor][:FontFile2][:Length1])
179
182
  assert_equal(File.binread(@font_file),
180
- @font_wrapper.dict[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream)
183
+ @font_wrapper.pdf_object[:DescendantFonts][0][:FontDescriptor][:FontFile2].stream)
181
184
  end
182
185
  end
183
186
  end
@@ -12,6 +12,15 @@ describe HexaPDF::Font::Type1Wrapper do
12
12
  @symbol_wrapper = HexaPDF::Font::Type1Wrapper.new(@doc, FONT_SYMBOL)
13
13
  end
14
14
 
15
+ it "can be used with an existing PDF object" do
16
+ font = @doc.add({Type: :Font, Subtype: :Type1, Encoding: {Differences: [65, :B]},
17
+ BaseFont: :"Times-Roman"})
18
+ wrapper = HexaPDF::Font::Type1Wrapper.new(@doc, FONT_TIMES, pdf_object: font)
19
+ assert_equal([:B, :E, :A, :S, :T], wrapper.decode_utf8("BEAST").map(&:name))
20
+ assert_equal("A", wrapper.encode(wrapper.glyph(:A)))
21
+ assert_equal("A", wrapper.encode(wrapper.glyph(:B)))
22
+ end
23
+
15
24
  it "returns 1 for the scaling factor" do
16
25
  assert_equal(1, @times_wrapper.scaling_factor)
17
26
  end
@@ -21,6 +30,10 @@ describe HexaPDF::Font::Type1Wrapper do
21
30
  assert_equal([:T, :e, :s, :t], @times_wrapper.decode_utf8("Test").map(&:name))
22
31
  end
23
32
 
33
+ it "falls back to the internal font encoding if the Unicode codepoint is not mapped" do
34
+ assert_equal([:Delta, :Delta], @symbol_wrapper.decode_utf8("D∆").map(&:name))
35
+ end
36
+
24
37
  it "UTF-8 characters for which no glyph name exists, are mapped to InvalidGlyph objects" do
25
38
  glyphs = @times_wrapper.decode_utf8("😁")
26
39
  assert_equal(1, glyphs.length)
@@ -58,7 +71,7 @@ describe HexaPDF::Font::Type1Wrapper do
58
71
  code = @times_wrapper.encode(@times_wrapper.glyph(:a))
59
72
  @doc.dispatch_message(:complete_objects)
60
73
  assert_equal("a", code)
61
- assert_equal(:WinAnsiEncoding, @times_wrapper.dict[:Encoding])
74
+ assert_equal(:WinAnsiEncoding, @times_wrapper.pdf_object[:Encoding])
62
75
  end
63
76
 
64
77
  it "fails if an InvalidGlyph is encoded" do
@@ -70,13 +83,25 @@ describe HexaPDF::Font::Type1Wrapper do
70
83
  end
71
84
  end
72
85
 
73
- describe "uses an empty encoding as initial encoding for symbolic fonts" do
74
- it "returns the PDF font dictionary and encoded glyph" do
75
- code = @symbol_wrapper.encode(@symbol_wrapper.glyph(:plus))
76
- @doc.dispatch_message(:complete_objects)
77
- assert_equal("\x21", code)
78
- assert_equal({Differences: [32, :space, :plus]}, @symbol_wrapper.dict[:Encoding].value)
79
- end
86
+ it "uses the font's internal encoding for fonts with the Special character set" do
87
+ code = @symbol_wrapper.encode(@symbol_wrapper.glyph(:plus))
88
+ @doc.dispatch_message(:complete_objects)
89
+ assert_equal("+", code)
90
+ assert_nil(@symbol_wrapper.pdf_object[:Encoding])
91
+ end
92
+
93
+ it "uses an empty encoding as initial encoding if a custom encoding is needed" do
94
+ wrapper = HexaPDF::Font::Type1Wrapper.new(@doc, FONT_TIMES, custom_encoding: true)
95
+ code = wrapper.encode(wrapper.glyph(:plus))
96
+ @doc.dispatch_message(:complete_objects)
97
+ assert_equal("\x21", code)
98
+ assert_equal({Differences: [32, :space, :plus]}, wrapper.pdf_object[:Encoding].value)
99
+ end
100
+ end
101
+
102
+ describe "creates the necessary PDF dictionaries" do
103
+ it "sets the circular reference" do
104
+ assert_same(@times_wrapper, @times_wrapper.pdf_object.font_wrapper)
80
105
  end
81
106
  end
82
107
  end
@@ -537,7 +537,7 @@ describe HexaPDF::Layout::Style::LinkLayer do
537
537
  end
538
538
 
539
539
  it "does nothing if the context is not a page object" do
540
- @canvas = HexaPDF::Document.new.add({Type: :XObject, Subtype: :Form}).canvas
540
+ @canvas = HexaPDF::Document.new.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 1, 1]}).canvas
541
541
  assert_nil(call_link(dest: true))
542
542
  end
543
543
 
@@ -674,10 +674,9 @@ describe HexaPDF::Layout::TextLayouter do
674
674
  pos = [0, 0]
675
675
  result.select! {|name, _| name == :set_text_matrix || name == :move_text_next_line }.
676
676
  map! do |name, ops|
677
- if name == :set_text_matrix
678
- pos = ops[-2, 2]
679
- elsif name == :move_text_next_line
680
- pos[1] -= leading
677
+ case name
678
+ when :set_text_matrix then pos = ops[-2, 2]
679
+ when :move_text_next_line then pos[1] -= leading
681
680
  end
682
681
  pos.dup
683
682
  end
@@ -66,8 +66,8 @@ describe HexaPDF::Configuration do
66
66
  assert_equal(HexaPDF, @config.constantize('test', 1))
67
67
  end
68
68
 
69
- def assert_constantize_error # :nodoc:
70
- exp = assert_raises(HexaPDF::Error) { yield }
69
+ def assert_constantize_error(&block) # :nodoc:
70
+ exp = assert_raises(HexaPDF::Error, &block)
71
71
  assert_match(/Error getting constant for configuration option/, exp.message)
72
72
  end
73
73
 
@@ -14,7 +14,9 @@ describe HexaPDF::Dictionary do
14
14
  end
15
15
 
16
16
  def add(obj)
17
- HexaPDF::Object.new(obj, oid: 1)
17
+ klass = HexaPDF::Object
18
+ klass = HexaPDF::Dictionary if obj.kind_of?(HexaPDF::Dictionary) || obj.kind_of?(Hash)
19
+ klass.new(obj, oid: 1)
18
20
  end
19
21
 
20
22
  def delete(_obj)