hexapdf 0.10.0 → 0.11.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/CONTRIBUTERS +1 -1
  4. data/Rakefile +35 -50
  5. data/VERSION +1 -1
  6. data/lib/hexapdf/cli.rb +4 -0
  7. data/lib/hexapdf/cli/command.rb +6 -2
  8. data/lib/hexapdf/cli/image2pdf.rb +141 -0
  9. data/lib/hexapdf/cli/info.rb +1 -1
  10. data/lib/hexapdf/cli/inspect.rb +32 -2
  11. data/lib/hexapdf/cli/modify.rb +1 -1
  12. data/lib/hexapdf/cli/optimize.rb +1 -1
  13. data/lib/hexapdf/cli/watermark.rb +130 -0
  14. data/lib/hexapdf/composer.rb +2 -2
  15. data/lib/hexapdf/configuration.rb +7 -1
  16. data/lib/hexapdf/content/canvas.rb +2 -2
  17. data/lib/hexapdf/content/graphic_object/arc.rb +2 -2
  18. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
  19. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  20. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  21. data/lib/hexapdf/dictionary.rb +11 -3
  22. data/lib/hexapdf/dictionary_fields.rb +32 -3
  23. data/lib/hexapdf/document.rb +7 -3
  24. data/lib/hexapdf/document/files.rb +1 -1
  25. data/lib/hexapdf/document/fonts.rb +21 -1
  26. data/lib/hexapdf/document/pages.rb +2 -2
  27. data/lib/hexapdf/encryption/standard_security_handler.rb +2 -2
  28. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  29. data/lib/hexapdf/font/true_type/table/head.rb +2 -2
  30. data/lib/hexapdf/font/true_type/table/os2.rb +4 -4
  31. data/lib/hexapdf/font/true_type_wrapper.rb +16 -16
  32. data/lib/hexapdf/font/type1_wrapper.rb +16 -16
  33. data/lib/hexapdf/font_loader.rb +2 -0
  34. data/lib/hexapdf/font_loader/from_configuration.rb +5 -0
  35. data/lib/hexapdf/font_loader/standard14.rb +5 -0
  36. data/lib/hexapdf/image_loader/png.rb +1 -1
  37. data/lib/hexapdf/layout/box.rb +2 -2
  38. data/lib/hexapdf/layout/image_box.rb +1 -1
  39. data/lib/hexapdf/layout/style.rb +50 -24
  40. data/lib/hexapdf/layout/text_box.rb +1 -1
  41. data/lib/hexapdf/layout/text_fragment.rb +2 -2
  42. data/lib/hexapdf/layout/text_layouter.rb +14 -10
  43. data/lib/hexapdf/name_tree_node.rb +3 -3
  44. data/lib/hexapdf/number_tree_node.rb +3 -3
  45. data/lib/hexapdf/pdf_array.rb +207 -0
  46. data/lib/hexapdf/rectangle.rb +12 -12
  47. data/lib/hexapdf/serializer.rb +1 -1
  48. data/lib/hexapdf/stream.rb +6 -4
  49. data/lib/hexapdf/task/optimize.rb +3 -3
  50. data/lib/hexapdf/type.rb +2 -0
  51. data/lib/hexapdf/type/acro_form.rb +51 -0
  52. data/lib/hexapdf/type/acro_form/field.rb +129 -0
  53. data/lib/hexapdf/type/acro_form/form.rb +124 -0
  54. data/lib/hexapdf/type/action.rb +1 -1
  55. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  56. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  57. data/lib/hexapdf/type/actions/launch.rb +1 -1
  58. data/lib/hexapdf/type/annotation.rb +2 -2
  59. data/lib/hexapdf/type/annotations.rb +1 -0
  60. data/lib/hexapdf/type/annotations/link.rb +4 -15
  61. data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -1
  62. data/lib/hexapdf/type/annotations/text.rb +3 -6
  63. data/lib/hexapdf/type/annotations/widget.rb +90 -0
  64. data/lib/hexapdf/type/catalog.rb +12 -9
  65. data/lib/hexapdf/type/cid_font.rb +3 -3
  66. data/lib/hexapdf/type/file_specification.rb +2 -2
  67. data/lib/hexapdf/type/font_descriptor.rb +5 -2
  68. data/lib/hexapdf/type/font_simple.rb +1 -1
  69. data/lib/hexapdf/type/font_type0.rb +1 -1
  70. data/lib/hexapdf/type/font_type3.rb +1 -1
  71. data/lib/hexapdf/type/form.rb +2 -2
  72. data/lib/hexapdf/type/graphics_state_parameter.rb +11 -6
  73. data/lib/hexapdf/type/icon_fit.rb +58 -0
  74. data/lib/hexapdf/type/image.rb +14 -8
  75. data/lib/hexapdf/type/info.rb +2 -1
  76. data/lib/hexapdf/type/page.rb +4 -4
  77. data/lib/hexapdf/type/page_tree_node.rb +3 -7
  78. data/lib/hexapdf/type/resources.rb +1 -1
  79. data/lib/hexapdf/type/trailer.rb +4 -4
  80. data/lib/hexapdf/type/viewer_preferences.rb +7 -4
  81. data/lib/hexapdf/type/xref_stream.rb +2 -2
  82. data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
  83. data/lib/hexapdf/version.rb +1 -1
  84. data/man/man1/hexapdf.1 +77 -8
  85. data/test/hexapdf/content/test_canvas.rb +2 -2
  86. data/test/hexapdf/content/test_processor.rb +3 -3
  87. data/test/hexapdf/document/test_files.rb +4 -4
  88. data/test/hexapdf/document/test_fonts.rb +13 -1
  89. data/test/hexapdf/document/test_images.rb +6 -6
  90. data/test/hexapdf/document/test_pages.rb +8 -8
  91. data/test/hexapdf/encryption/test_security_handler.rb +7 -7
  92. data/test/hexapdf/encryption/test_standard_security_handler.rb +5 -5
  93. data/test/hexapdf/font/test_true_type_wrapper.rb +2 -2
  94. data/test/hexapdf/font_loader/test_from_configuration.rb +4 -0
  95. data/test/hexapdf/font_loader/test_standard14.rb +10 -0
  96. data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
  97. data/test/hexapdf/image_loader/test_png.rb +3 -3
  98. data/test/hexapdf/layout/test_box.rb +2 -2
  99. data/test/hexapdf/layout/test_frame.rb +1 -1
  100. data/test/hexapdf/layout/test_image_box.rb +1 -1
  101. data/test/hexapdf/layout/test_style.rb +18 -13
  102. data/test/hexapdf/layout/test_text_box.rb +1 -1
  103. data/test/hexapdf/layout/test_text_layouter.rb +11 -6
  104. data/test/hexapdf/task/test_dereference.rb +2 -2
  105. data/test/hexapdf/task/test_optimize.rb +11 -11
  106. data/test/hexapdf/test_composer.rb +1 -1
  107. data/test/hexapdf/test_dictionary.rb +10 -2
  108. data/test/hexapdf/test_dictionary_fields.rb +27 -3
  109. data/test/hexapdf/test_document.rb +16 -15
  110. data/test/hexapdf/test_importer.rb +4 -4
  111. data/test/hexapdf/test_object.rb +1 -1
  112. data/test/hexapdf/test_pdf_array.rb +162 -0
  113. data/test/hexapdf/test_rectangle.rb +3 -5
  114. data/test/hexapdf/test_serializer.rb +1 -1
  115. data/test/hexapdf/test_stream.rb +1 -0
  116. data/test/hexapdf/test_writer.rb +3 -3
  117. data/test/hexapdf/type/acro_form/test_field.rb +85 -0
  118. data/test/hexapdf/type/acro_form/test_form.rb +69 -0
  119. data/test/hexapdf/type/annotations/test_text.rb +2 -6
  120. data/test/hexapdf/type/annotations/test_widget.rb +24 -0
  121. data/test/hexapdf/type/test_annotation.rb +1 -1
  122. data/test/hexapdf/type/test_catalog.rb +1 -1
  123. data/test/hexapdf/type/test_cid_font.rb +3 -3
  124. data/test/hexapdf/type/test_font.rb +2 -2
  125. data/test/hexapdf/type/test_font_descriptor.rb +2 -1
  126. data/test/hexapdf/type/test_font_simple.rb +3 -3
  127. data/test/hexapdf/type/test_font_true_type.rb +6 -6
  128. data/test/hexapdf/type/test_font_type0.rb +5 -5
  129. data/test/hexapdf/type/test_font_type1.rb +8 -8
  130. data/test/hexapdf/type/test_font_type3.rb +4 -4
  131. data/test/hexapdf/type/test_image.rb +16 -12
  132. data/test/hexapdf/type/test_page.rb +11 -11
  133. data/test/hexapdf/type/test_page_tree_node.rb +20 -20
  134. data/test/hexapdf/type/test_resources.rb +6 -6
  135. data/test/hexapdf/type/test_trailer.rb +5 -2
  136. data/test/hexapdf/type/test_xref_stream.rb +1 -0
  137. data/test/hexapdf/utils/test_sorted_tree_node.rb +35 -35
  138. metadata +23 -7
  139. data/test/hexapdf/type/annotations/test_link.rb +0 -19
@@ -777,9 +777,9 @@ describe HexaPDF::Content::Canvas do
777
777
 
778
778
  describe "xobject" do
779
779
  before do
780
- @image = @doc.add(Type: :XObject, Subtype: :Image, Width: 10, Height: 5)
780
+ @image = @doc.add({Type: :XObject, Subtype: :Image, Width: 10, Height: 5})
781
781
  @image.source_path = File.join(TEST_DATA_DIR, 'images', 'gray.jpg')
782
- @form = @doc.add(Type: :XObject, Subtype: :Form, BBox: [100, 50, 200, 100])
782
+ @form = @doc.add({Type: :XObject, Subtype: :Form, BBox: [100, 50, 200, 100]})
783
783
  end
784
784
 
785
785
  it "can use any xobject specified via a filename" do
@@ -117,9 +117,9 @@ describe HexaPDF::Content::Processor do
117
117
  before do
118
118
  @doc = HexaPDF::Document.new
119
119
  @processor.process(:BT)
120
- @processor.graphics_state.font = @font = @doc.add(Type: :Font, Subtype: :Type1,
121
- Encoding: :WinAnsiEncoding,
122
- BaseFont: :"Times-Roman")
120
+ @processor.graphics_state.font = @font = @doc.add({Type: :Font, Subtype: :Type1,
121
+ Encoding: :WinAnsiEncoding,
122
+ BaseFont: :"Times-Roman"})
123
123
  @processor.graphics_state.font_size = 10
124
124
  @processor.graphics_state.text_rise = 10
125
125
  @processor.graphics_state.character_spacing = 1
@@ -50,9 +50,9 @@ describe HexaPDF::Document::Files do
50
50
 
51
51
  describe "each" do
52
52
  it "iterates only over named embedded files and file annotations if search=false" do
53
- @doc.add(Type: :Filespec)
53
+ @doc.add({Type: :Filespec})
54
54
  spec1 = @doc.files.add(__FILE__)
55
- spec2 = @doc.add(Type: :Filespec)
55
+ spec2 = @doc.add({Type: :Filespec})
56
56
  @doc.pages.add # page without annot
57
57
  @doc.pages.add[:Annots] = [
58
58
  {Subtype: :FileAttachment, FS: HexaPDF::Reference.new(spec1.oid, spec1.gen)},
@@ -64,8 +64,8 @@ describe HexaPDF::Document::Files do
64
64
 
65
65
  it "iterates over all file specifications of the document if search=true" do
66
66
  specs = []
67
- specs << @doc.add(Type: :Filespec)
68
- specs << @doc.add(Type: :Filespec)
67
+ specs << @doc.add({Type: :Filespec})
68
+ specs << @doc.add({Type: :Filespec})
69
69
  assert_equal(specs, @doc.files.each(search: true).to_a)
70
70
  end
71
71
  end
@@ -37,7 +37,9 @@ describe HexaPDF::Document::Fonts do
37
37
  end
38
38
 
39
39
  it "fails if the requested font is not found" do
40
- assert_raises(HexaPDF::Error) { @doc.fonts.add("Unknown") }
40
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::Standard14'
41
+ error = assert_raises(HexaPDF::Error) { @doc.fonts.add("Unknown") }
42
+ assert_match(/Times \(none/, error.message)
41
43
  end
42
44
 
43
45
  it "raises an error if a font loader cannot be correctly retrieved" do
@@ -45,4 +47,14 @@ describe HexaPDF::Document::Fonts do
45
47
  assert_raises(HexaPDF::Error) { @doc.fonts.add(:Other) }
46
48
  end
47
49
  end
50
+
51
+ it "returns the configured fonts" do
52
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::Standard14'
53
+ @doc.config['font_loader'] << 'HexaPDF::FontLoader::FromConfiguration'
54
+ @doc.config['font.map'] = {'Times' => {heavy: 'none', none: 'none'}, 'Other' => {none: 'none'}}
55
+ fonts = @doc.fonts.configured_fonts
56
+ assert_equal([:none], fonts['Symbol'])
57
+ assert_equal([:none, :bold, :italic, :bold_italic, :heavy], fonts['Times'])
58
+ assert_equal([:none], fonts['Other'])
59
+ end
48
60
  end
@@ -60,12 +60,12 @@ describe HexaPDF::Document::Images do
60
60
  it "iterates over all non-mask images" do
61
61
  @doc.add(5)
62
62
  images = []
63
- images << @doc.add(Type: :XObject, Subtype: :Image)
64
- images << @doc.add(Type: :XObject, Subtype: :Image, Mask: [5, 6])
65
- images << @doc.add(Type: :XObject, Subtype: :Image,
66
- Mask: @doc.add(Type: :XObject, Subtype: :Image))
67
- images << @doc.add(Type: :XObject, Subtype: :Image,
68
- SMask: @doc.add(Type: :XObject, Subtype: :Image))
63
+ images << @doc.add({Type: :XObject, Subtype: :Image})
64
+ images << @doc.add({Type: :XObject, Subtype: :Image, Mask: [5, 6]})
65
+ images << @doc.add({Type: :XObject, Subtype: :Image,
66
+ Mask: @doc.add({Type: :XObject, Subtype: :Image})})
67
+ images << @doc.add({Type: :XObject, Subtype: :Image,
68
+ SMask: @doc.add({Type: :XObject, Subtype: :Image})})
69
69
  assert_equal(images.sort, @doc.images.to_a.sort)
70
70
  end
71
71
  end
@@ -17,7 +17,7 @@ describe HexaPDF::Document::Pages do
17
17
  describe "add" do
18
18
  it "adds a new empty page when no page is given" do
19
19
  page = @doc.pages.add
20
- assert_equal([page], @doc.pages.root[:Kids])
20
+ assert_equal([page], @doc.pages.root[:Kids].value)
21
21
  end
22
22
 
23
23
  it "adds a new empty page with the given dimensions" do
@@ -34,9 +34,9 @@ describe HexaPDF::Document::Pages do
34
34
 
35
35
  it "adds the given page to the end" do
36
36
  page = @doc.pages.add
37
- new_page = @doc.add(Type: :Page)
37
+ new_page = @doc.add({Type: :Page})
38
38
  assert_same(new_page, @doc.pages.add(new_page))
39
- assert_equal([page, new_page], @doc.pages.root[:Kids])
39
+ assert_equal([page, new_page], @doc.pages.root[:Kids].value)
40
40
  end
41
41
 
42
42
  it "fails if an unknown page format is given" do
@@ -46,10 +46,10 @@ describe HexaPDF::Document::Pages do
46
46
 
47
47
  describe "<<" do
48
48
  it "works like add but always needs a page returns self" do
49
- page1 = @doc.add(Type: :Page)
50
- page2 = @doc.add(Type: :Page)
49
+ page1 = @doc.add({Type: :Page})
50
+ page2 = @doc.add({Type: :Page})
51
51
  @doc.pages << page1 << page2
52
- assert_equal([page1, page2], @doc.pages.root[:Kids])
52
+ assert_equal([page1, page2], @doc.pages.root[:Kids].value)
53
53
  end
54
54
  end
55
55
 
@@ -66,7 +66,7 @@ describe HexaPDF::Document::Pages do
66
66
  end
67
67
 
68
68
  it "insert a given page at a given index" do
69
- new_page = @doc.add(Type: :Page)
69
+ new_page = @doc.add({Type: :Page})
70
70
  assert_same(new_page, @doc.pages.insert(2, new_page))
71
71
  assert_equal(new_page, @doc.pages.root[:Kids][2])
72
72
  end
@@ -88,7 +88,7 @@ describe HexaPDF::Document::Pages do
88
88
  page2 = @doc.pages.add
89
89
  page3 = @doc.pages.add
90
90
  assert_same(page2, @doc.pages.delete_at(1))
91
- assert_equal([page1, page3], @doc.pages.root[:Kids])
91
+ assert_equal([page1, page3], @doc.pages.root[:Kids].value)
92
92
  end
93
93
  end
94
94
 
@@ -201,14 +201,14 @@ describe HexaPDF::Encryption::SecurityHandler do
201
201
 
202
202
  describe "set_up_decryption" do
203
203
  it "wraps the given hash in an encryption dictionary class, uses it for its dict, returns it" do
204
- dict = @handler.set_up_decryption(Filter: :test, V: 1)
204
+ dict = @handler.set_up_decryption({Filter: :test, V: 1})
205
205
  assert_equal(dict, @handler.dict)
206
206
  assert_kind_of(HexaPDF::Encryption::EncryptionDictionary, @handler.dict)
207
207
  assert_equal({Filter: :test, V: 1}, @handler.dict.value)
208
208
  end
209
209
 
210
210
  it "doesn't modify the trailer's /Encrypt dictionary" do
211
- @handler.set_up_decryption(Filter: :test, V: 4, Length: 128)
211
+ @handler.set_up_decryption({Filter: :test, V: 4, Length: 128})
212
212
  assert_nil(@document.trailer[:Encrypt])
213
213
  end
214
214
 
@@ -238,8 +238,8 @@ describe HexaPDF::Encryption::SecurityHandler do
238
238
  end
239
239
 
240
240
  it "selects the correct algorithm for string, stream and embedded file decryption" do
241
- @handler.set_up_decryption(V: 4, StrF: :Mine, StmF: :Mine, EFF: :Mine,
242
- CF: {Mine: {CFM: :V2}})
241
+ @handler.set_up_decryption({V: 4, StrF: :Mine, StmF: :Mine, EFF: :Mine,
242
+ CF: {Mine: {CFM: :V2}}})
243
243
  assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:embedded_file_algorithm))
244
244
  assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:string_algorithm))
245
245
  assert_equal(HexaPDF::Encryption::FastARC4, @handler.send(:stream_algorithm))
@@ -254,14 +254,14 @@ describe HexaPDF::Encryption::SecurityHandler do
254
254
 
255
255
  it "fails for unsupported /V values in the dict" do
256
256
  exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
257
- @handler.set_up_decryption(V: 3)
257
+ @handler.set_up_decryption({V: 3})
258
258
  end
259
259
  assert_match(/Unsupported encryption version/i, exp.message)
260
260
  end
261
261
 
262
262
  it "fails for unsupported crypt filter encryption methods" do
263
263
  exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
264
- @handler.set_up_decryption(V: 4, StrF: :Mine, CF: {Mine: {CFM: :Unknown}})
264
+ @handler.set_up_decryption({V: 4, StrF: :Mine, CF: {Mine: {CFM: :Unknown}}})
265
265
  end
266
266
  assert_match(/Unsupported encryption method/i, exp.message)
267
267
  end
@@ -269,7 +269,7 @@ describe HexaPDF::Encryption::SecurityHandler do
269
269
 
270
270
  describe "decrypt" do
271
271
  before do
272
- @handler.set_up_decryption(V: 1)
272
+ @handler.set_up_decryption({V: 1})
273
273
  @encrypted = @handler.encrypt_string('string', @obj)
274
274
  @obj.value = {Key: @encrypted.dup, Array: [@encrypted.dup], Hash: {Another: @encrypted.dup}}
275
275
  end
@@ -217,29 +217,29 @@ describe HexaPDF::Encryption::StandardSecurityHandler do
217
217
  describe "prepare_decryption" do
218
218
  it "fails if the /Filter value is incorrect" do
219
219
  exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
220
- @handler.set_up_decryption(Filter: :NonStandard, V: 2)
220
+ @handler.set_up_decryption({Filter: :NonStandard, V: 2})
221
221
  end
222
222
  assert_match(/Invalid \/Filter/i, exp.message)
223
223
  end
224
224
 
225
225
  it "fails if the /R value is incorrect" do
226
226
  exp = assert_raises(HexaPDF::UnsupportedEncryptionError) do
227
- @handler.set_up_decryption(Filter: :Standard, V: 2, R: 5)
227
+ @handler.set_up_decryption({Filter: :Standard, V: 2, R: 5})
228
228
  end
229
229
  assert_match(/Invalid \/R/i, exp.message)
230
230
  end
231
231
 
232
232
  it "fails if the ID in the document's trailer is missing although it is needed" do
233
233
  exp = assert_raises(HexaPDF::EncryptionError) do
234
- @handler.set_up_decryption(Filter: :Standard, V: 2, R: 2)
234
+ @handler.set_up_decryption({Filter: :Standard, V: 2, R: 2})
235
235
  end
236
236
  assert_match(/Document ID/i, exp.message)
237
237
  end
238
238
 
239
239
  it "fails if the supplied password is invalid" do
240
240
  exp = assert_raises(HexaPDF::EncryptionError) do
241
- @handler.set_up_decryption(Filter: :Standard, V: 2, R: 6, U: 'a' * 48, O: 'a' * 48,
242
- UE: 'a' * 32, OE: 'a' * 32)
241
+ @handler.set_up_decryption({Filter: :Standard, V: 2, R: 6, U: 'a' * 48, O: 'a' * 48,
242
+ UE: 'a' * 32, OE: 'a' * 32})
243
243
  end
244
244
  assert_match(/Invalid password/i, exp.message)
245
245
  end
@@ -114,7 +114,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
114
114
  cidfont[:CIDSystemInfo].value)
115
115
  assert_equal(:Identity, cidfont[:CIDToGIDMap])
116
116
  assert_equal(@font_wrapper.glyph(3).width, cidfont[:DW])
117
- assert_equal([2, [glyph.width]], cidfont[:W])
117
+ assert_equal([2, [glyph.width]], cidfont[:W].value)
118
118
  assert(cidfont.validate)
119
119
 
120
120
  # Checking font descriptor
@@ -155,7 +155,7 @@ describe HexaPDF::Font::TrueTypeWrapper do
155
155
 
156
156
  assert_equal(HexaPDF::Font::CMap.create_to_unicode_cmap([[3, ' '.ord], [glyph.id, 'H'.ord]]),
157
157
  dict[:ToUnicode].stream)
158
- assert_equal([glyph.id, [glyph.width]], dict[:DescendantFonts][0][:W])
158
+ assert_equal([glyph.id, [glyph.width]], dict[:DescendantFonts][0][:W].value)
159
159
  end
160
160
  end
161
161
 
@@ -32,4 +32,8 @@ describe HexaPDF::FontLoader::FromConfiguration do
32
32
  it "returns nil for unknown fonts" do
33
33
  assert_nil(@klass.call(@doc, "Unknown"))
34
34
  end
35
+
36
+ it "returns a hash with all configured fonts" do
37
+ assert_equal({'font' => [:none]}, @klass.available_fonts(@doc))
38
+ end
35
39
  end
@@ -20,4 +20,14 @@ describe HexaPDF::FontLoader::Standard14 do
20
20
  it "returns nil for unknown fonts" do
21
21
  assert_nil(@obj.call(@doc, "Unknown"))
22
22
  end
23
+
24
+ it "returns a hash with all standard PDF fonts" do
25
+ assert_equal({
26
+ 'Times' => [:none, :bold, :italic, :bold_italic],
27
+ 'Helvetica' => [:none, :bold, :italic, :bold_italic],
28
+ 'Courier' => [:none, :bold, :italic, :bold_italic],
29
+ 'Symbol' => [:none], 'ZapfDingbats' => [:none]
30
+ },
31
+ @obj.available_fonts(@doc))
32
+ end
23
33
  end
@@ -62,7 +62,7 @@ describe HexaPDF::ImageLoader::JPEG do
62
62
  assert_equal(5, image[:Width])
63
63
  assert_equal(5, image[:Height])
64
64
  assert_equal(:DeviceCMYK, image[:ColorSpace])
65
- assert_equal([1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0], image[:Decode])
65
+ assert_equal([1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0], image[:Decode].value)
66
66
  assert_equal(File.binread(jpeg), image.stream)
67
67
  end
68
68
 
@@ -29,7 +29,7 @@ describe HexaPDF::ImageLoader::PNG do
29
29
  assert_equal(width, image[:Width])
30
30
  assert_equal(height, image[:Height])
31
31
  assert_equal(bpc, image[:BitsPerComponent])
32
- assert_equal(color_space, image[:ColorSpace]) if color_space
32
+ assert_equal(color_space, @doc.unwrap(image[:ColorSpace])) if color_space
33
33
  data = stream.map {|row| [row.map {|i| i.to_s(2).rjust(bpc, '0') }.join("")].pack('B*') }.join("")
34
34
  assert_equal(data, image.stream)
35
35
  end
@@ -111,7 +111,7 @@ describe HexaPDF::ImageLoader::PNG do
111
111
  [253, 202, 151, 100, 50],
112
112
  [253, 202, 151, 100, 49]]
113
113
  assert_image(image, 5, 5, 8, :DeviceGray, data)
114
- assert_equal([203, 203], image[:Mask])
114
+ assert_equal([203, 203], image[:Mask].value)
115
115
  end
116
116
 
117
117
  it "works for a greyscale png with a gamma value of 1" do
@@ -123,7 +123,7 @@ describe HexaPDF::ImageLoader::PNG do
123
123
  it "works for a greyscale png with a gamma value of 1/1.5" do
124
124
  png = @images.grep(/greyscale-with-gamma1\.5\.png/).first
125
125
  image = @loader.load(@doc, png)
126
- assert_equal([:CalGray, {WhitePoint: [1.0, 1.0, 1.0], Gamma: 1 / 1.5}], image[:ColorSpace])
126
+ assert_equal([:CalGray, {WhitePoint: [1.0, 1.0, 1.0], Gamma: 1 / 1.5}], image[:ColorSpace].value)
127
127
  end
128
128
 
129
129
  it "works for an indexed 1-bit png" do
@@ -6,8 +6,8 @@ require 'hexapdf/document'
6
6
  require 'hexapdf/layout/box'
7
7
 
8
8
  describe HexaPDF::Layout::Box do
9
- def create_box(*args, &block)
10
- HexaPDF::Layout::Box.new(*args, &block)
9
+ def create_box(**args, &block)
10
+ HexaPDF::Layout::Box.new(**args, &block)
11
11
  end
12
12
 
13
13
  describe "::create" do
@@ -50,7 +50,7 @@ describe HexaPDF::Layout::Frame do
50
50
  # checked whether the box coordinates are pos and whether the frame has the shape given by
51
51
  # points.
52
52
  def check_box(box_opts, pos, points)
53
- @box = HexaPDF::Layout::Box.create(box_opts) {}
53
+ @box = HexaPDF::Layout::Box.create(**box_opts) {}
54
54
  @canvas.expect(:translate, nil, pos)
55
55
  assert(@frame.draw(@canvas, @box))
56
56
  assert_equal(points, @frame.shape.polygons.map(&:to_a))
@@ -13,7 +13,7 @@ describe HexaPDF::Layout::ImageBox do
13
13
  end
14
14
 
15
15
  def create_box(**kwargs)
16
- HexaPDF::Layout::ImageBox.new(@image, kwargs)
16
+ HexaPDF::Layout::ImageBox.new(@image, **kwargs)
17
17
  end
18
18
 
19
19
  describe "initialize" do
@@ -136,8 +136,8 @@ describe HexaPDF::Layout::Style::Quad do
136
136
  end
137
137
 
138
138
  describe HexaPDF::Layout::Style::Border do
139
- def create_border(*args)
140
- HexaPDF::Layout::Style::Border.new(*args)
139
+ def create_border(**args)
140
+ HexaPDF::Layout::Style::Border.new(**args)
141
141
  end
142
142
 
143
143
  it "has accessors for with, color and style that return Quads" do
@@ -531,13 +531,13 @@ describe HexaPDF::Layout::Style::LinkLayer do
531
531
  end
532
532
 
533
533
  def call_link(hash)
534
- link = HexaPDF::Layout::Style::LinkLayer.new(hash)
534
+ link = HexaPDF::Layout::Style::LinkLayer.new(**hash)
535
535
  link.call(@canvas, @box)
536
536
  @canvas.context[:Annots]&.first
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}).canvas
541
541
  assert_nil(call_link(dest: true))
542
542
  end
543
543
 
@@ -545,28 +545,28 @@ describe HexaPDF::Layout::Style::LinkLayer do
545
545
  annot = call_link(dest: true)
546
546
  assert_equal(:Link, annot[:Subtype])
547
547
  assert_equal([10, 10, 25, 20], annot[:Rect].value)
548
- assert_equal([10, 10, 25, 10, 25, 20, 10, 20], annot[:QuadPoints])
548
+ assert_equal([10, 10, 25, 10, 25, 20, 10, 20], annot[:QuadPoints].value)
549
549
  end
550
550
 
551
551
  it "removes the border by default" do
552
552
  annot = call_link(dest: true)
553
- assert_equal([0, 0, 0], annot[:Border])
553
+ assert_equal([0, 0, 0], annot[:Border].value)
554
554
  end
555
555
 
556
556
  it "uses a default border if no specific border style is specified" do
557
557
  annot = call_link(dest: true, border: true)
558
- assert_equal([0, 0, 1], annot[:Border])
558
+ assert_equal([0, 0, 1], annot[:Border].value)
559
559
  end
560
560
 
561
561
  it "uses the specified border and border color" do
562
562
  annot = call_link(dest: true, border: [10, 10, 2], border_color: [255])
563
- assert_equal([10, 10, 2], annot[:Border])
564
- assert_equal([1.0], annot[:C])
563
+ assert_equal([10, 10, 2], annot[:Border].value)
564
+ assert_equal([1.0], annot[:C].value)
565
565
  end
566
566
 
567
567
  it "works for simple destinations" do
568
568
  annot = call_link(dest: [@canvas.context, :FitH])
569
- assert_equal([@canvas.context, :FitH], annot[:Dest])
569
+ assert_equal([@canvas.context, :FitH], annot[:Dest].value)
570
570
  assert_nil(annot[:A])
571
571
  end
572
572
 
@@ -641,14 +641,14 @@ describe HexaPDF::Layout::Style do
641
641
  assert_equal(100, @style.horizontal_scaling)
642
642
  assert_equal(0, @style.text_rise)
643
643
  assert_equal({}, @style.font_features)
644
- assert_equal(:fill, @style.text_rendering_mode)
644
+ assert_equal(HexaPDF::Content::TextRenderingMode::FILL, @style.text_rendering_mode)
645
645
  assert_equal([0], @style.fill_color.components)
646
646
  assert_equal(1, @style.fill_alpha)
647
647
  assert_equal([0], @style.stroke_color.components)
648
648
  assert_equal(1, @style.stroke_alpha)
649
649
  assert_equal(1, @style.stroke_width)
650
- assert_equal(:butt, @style.stroke_cap_style)
651
- assert_equal(:miter, @style.stroke_join_style)
650
+ assert_equal(HexaPDF::Content::LineCapStyle::BUTT_CAP, @style.stroke_cap_style)
651
+ assert_equal(HexaPDF::Content::LineJoinStyle::MITER_JOIN, @style.stroke_join_style)
652
652
  assert_equal(10.0, @style.stroke_miter_limit)
653
653
  assert_equal(:left, @style.align)
654
654
  assert_equal(:top, @style.valign)
@@ -677,6 +677,11 @@ describe HexaPDF::Layout::Style do
677
677
  assert_equal([[5], 2], @style.stroke_dash_pattern.to_operands)
678
678
  end
679
679
 
680
+ it "allows checking for valid values" do
681
+ error = assert_raises(ArgumentError) { @style.align = :none }
682
+ assert_match(/not a valid align value \(:left, :center, :right, :justify\)/, error.message)
683
+ end
684
+
680
685
  it "allows checking whether a property has been set or accessed" do
681
686
  refute(@style.align?)
682
687
  assert_equal(:left, @style.align)
@@ -12,7 +12,7 @@ describe HexaPDF::Layout::TextBox do
12
12
  end
13
13
 
14
14
  def create_box(items, **kwargs)
15
- HexaPDF::Layout::TextBox.new(items, kwargs)
15
+ HexaPDF::Layout::TextBox.new(items, **kwargs)
16
16
  end
17
17
 
18
18
  describe "initialize" do