hexapdf 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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