hexapdf 0.32.1 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/lib/hexapdf/cli/command.rb +5 -2
  19. data/lib/hexapdf/cli/form.rb +5 -5
  20. data/lib/hexapdf/cli/inspect.rb +3 -3
  21. data/lib/hexapdf/cli.rb +4 -0
  22. data/lib/hexapdf/composer.rb +104 -52
  23. data/lib/hexapdf/configuration.rb +44 -39
  24. data/lib/hexapdf/content/canvas.rb +393 -267
  25. data/lib/hexapdf/content/color_space.rb +72 -25
  26. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  27. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  28. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  29. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  30. data/lib/hexapdf/content/graphic_object.rb +6 -7
  31. data/lib/hexapdf/content/graphics_state.rb +54 -45
  32. data/lib/hexapdf/content/operator.rb +52 -54
  33. data/lib/hexapdf/content/parser.rb +2 -2
  34. data/lib/hexapdf/content/processor.rb +15 -15
  35. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  36. data/lib/hexapdf/content.rb +5 -0
  37. data/lib/hexapdf/dictionary.rb +6 -5
  38. data/lib/hexapdf/dictionary_fields.rb +42 -14
  39. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  40. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  41. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  42. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  43. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  44. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  45. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  46. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  47. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  48. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  49. data/lib/hexapdf/digital_signature.rb +7 -2
  50. data/lib/hexapdf/document/destinations.rb +12 -11
  51. data/lib/hexapdf/document/files.rb +1 -1
  52. data/lib/hexapdf/document/fonts.rb +1 -1
  53. data/lib/hexapdf/document/layout.rb +167 -39
  54. data/lib/hexapdf/document/pages.rb +3 -2
  55. data/lib/hexapdf/document.rb +89 -55
  56. data/lib/hexapdf/encryption/aes.rb +5 -5
  57. data/lib/hexapdf/encryption/arc4.rb +1 -1
  58. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  59. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/identity.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  62. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  63. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  64. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  65. data/lib/hexapdf/encryption.rb +7 -2
  66. data/lib/hexapdf/error.rb +18 -0
  67. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  68. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  69. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  70. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  71. data/lib/hexapdf/filter/pass_through.rb +1 -1
  72. data/lib/hexapdf/filter/predictor.rb +1 -1
  73. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  74. data/lib/hexapdf/filter.rb +55 -6
  75. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  76. data/lib/hexapdf/font/cmap.rb +1 -1
  77. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  79. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  80. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  82. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  83. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  84. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  85. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  86. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  87. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  88. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  89. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  90. data/lib/hexapdf/font_loader.rb +3 -0
  91. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  92. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  93. data/lib/hexapdf/image_loader/png.rb +2 -2
  94. data/lib/hexapdf/image_loader.rb +1 -1
  95. data/lib/hexapdf/importer.rb +13 -0
  96. data/lib/hexapdf/layout/box.rb +9 -2
  97. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  98. data/lib/hexapdf/layout/column_box.rb +18 -4
  99. data/lib/hexapdf/layout/frame.rb +30 -12
  100. data/lib/hexapdf/layout/image_box.rb +5 -0
  101. data/lib/hexapdf/layout/inline_box.rb +1 -0
  102. data/lib/hexapdf/layout/list_box.rb +17 -1
  103. data/lib/hexapdf/layout/page_style.rb +4 -4
  104. data/lib/hexapdf/layout/style.rb +18 -3
  105. data/lib/hexapdf/layout/table_box.rb +682 -0
  106. data/lib/hexapdf/layout/text_box.rb +5 -3
  107. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  108. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  109. data/lib/hexapdf/layout.rb +1 -0
  110. data/lib/hexapdf/name_tree_node.rb +1 -1
  111. data/lib/hexapdf/number_tree_node.rb +1 -1
  112. data/lib/hexapdf/object.rb +18 -7
  113. data/lib/hexapdf/parser.rb +8 -8
  114. data/lib/hexapdf/pdf_array.rb +1 -1
  115. data/lib/hexapdf/rectangle.rb +1 -1
  116. data/lib/hexapdf/reference.rb +1 -1
  117. data/lib/hexapdf/revision.rb +1 -1
  118. data/lib/hexapdf/revisions.rb +3 -3
  119. data/lib/hexapdf/serializer.rb +15 -15
  120. data/lib/hexapdf/stream.rb +4 -2
  121. data/lib/hexapdf/tokenizer.rb +14 -14
  122. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  123. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  125. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  126. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  128. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  130. data/lib/hexapdf/type/acro_form.rb +1 -1
  131. data/lib/hexapdf/type/action.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  133. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  134. data/lib/hexapdf/type/actions/launch.rb +1 -1
  135. data/lib/hexapdf/type/actions/uri.rb +1 -1
  136. data/lib/hexapdf/type/actions.rb +1 -1
  137. data/lib/hexapdf/type/annotation.rb +3 -3
  138. data/lib/hexapdf/type/annotations/link.rb +1 -1
  139. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  140. data/lib/hexapdf/type/annotations/text.rb +1 -1
  141. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  142. data/lib/hexapdf/type/annotations.rb +1 -1
  143. data/lib/hexapdf/type/catalog.rb +1 -1
  144. data/lib/hexapdf/type/cid_font.rb +3 -3
  145. data/lib/hexapdf/type/embedded_file.rb +1 -1
  146. data/lib/hexapdf/type/file_specification.rb +2 -2
  147. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  148. data/lib/hexapdf/type/font_simple.rb +2 -2
  149. data/lib/hexapdf/type/font_type0.rb +3 -3
  150. data/lib/hexapdf/type/font_type3.rb +1 -1
  151. data/lib/hexapdf/type/form.rb +1 -1
  152. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  153. data/lib/hexapdf/type/icon_fit.rb +1 -1
  154. data/lib/hexapdf/type/image.rb +1 -1
  155. data/lib/hexapdf/type/info.rb +1 -1
  156. data/lib/hexapdf/type/mark_information.rb +1 -1
  157. data/lib/hexapdf/type/names.rb +2 -2
  158. data/lib/hexapdf/type/object_stream.rb +7 -3
  159. data/lib/hexapdf/type/outline.rb +1 -1
  160. data/lib/hexapdf/type/outline_item.rb +1 -1
  161. data/lib/hexapdf/type/page.rb +19 -10
  162. data/lib/hexapdf/type/page_label.rb +1 -1
  163. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  164. data/lib/hexapdf/type/resources.rb +1 -1
  165. data/lib/hexapdf/type/trailer.rb +2 -2
  166. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  167. data/lib/hexapdf/type/xref_stream.rb +2 -2
  168. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  169. data/lib/hexapdf/version.rb +1 -1
  170. data/lib/hexapdf/writer.rb +4 -4
  171. data/lib/hexapdf/xref_section.rb +2 -2
  172. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  173. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  174. data/test/hexapdf/content/test_canvas.rb +0 -1
  175. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  176. data/test/hexapdf/document/test_files.rb +2 -2
  177. data/test/hexapdf/document/test_layout.rb +98 -0
  178. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  179. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  180. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  181. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  182. data/test/hexapdf/layout/test_box.rb +1 -1
  183. data/test/hexapdf/layout/test_column_box.rb +65 -21
  184. data/test/hexapdf/layout/test_frame.rb +14 -14
  185. data/test/hexapdf/layout/test_image_box.rb +4 -0
  186. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  187. data/test/hexapdf/layout/test_list_box.rb +40 -6
  188. data/test/hexapdf/layout/test_page_style.rb +3 -2
  189. data/test/hexapdf/layout/test_style.rb +50 -0
  190. data/test/hexapdf/layout/test_table_box.rb +722 -0
  191. data/test/hexapdf/layout/test_text_box.rb +18 -0
  192. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  193. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  194. data/test/hexapdf/test_document.rb +1 -0
  195. data/test/hexapdf/test_filter.rb +8 -0
  196. data/test/hexapdf/test_importer.rb +9 -0
  197. data/test/hexapdf/test_object.rb +16 -5
  198. data/test/hexapdf/test_parser.rb +1 -1
  199. data/test/hexapdf/test_stream.rb +7 -0
  200. data/test/hexapdf/test_writer.rb +3 -3
  201. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  202. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  203. data/test/hexapdf/type/test_object_stream.rb +9 -3
  204. data/test/hexapdf/type/test_page.rb +18 -4
  205. metadata +17 -8
@@ -107,6 +107,14 @@ describe HexaPDF::Layout::TextBox do
107
107
  assert_equal([nil, box], box.split(100, 100, @frame))
108
108
  end
109
109
 
110
+ it "works if the box fits exactly (+/- float divergence)" do
111
+ box = create_box([@inline_box] * 5)
112
+ box.fit(50, 10, @frame)
113
+ box.instance_variable_set(:@width, 50.00000000006)
114
+ box.instance_variable_set(:@height, 10.00000000003)
115
+ assert_equal([box], box.split(50, 10, @frame))
116
+ end
117
+
110
118
  it "splits the box if necessary when using non-flowing text" do
111
119
  box = create_box([@inline_box] * 10)
112
120
  boxes = box.split(50, 10, @frame)
@@ -125,6 +133,16 @@ describe HexaPDF::Layout::TextBox do
125
133
  assert_equal(box, boxes[0])
126
134
  assert_equal(5, boxes[1].instance_variable_get(:@items).length)
127
135
  end
136
+
137
+ it "correctly handles text indentation for split boxes" do
138
+ [{}, {position: :flow}].each do |styles|
139
+ box = create_box([@inline_box] * 202, style: {text_indent: 50, **styles})
140
+ boxes = box.split(100, 100, @frame)
141
+ assert_equal(107, boxes[1].instance_variable_get(:@items).length)
142
+ boxes = boxes[1].split(100, 100, @frame)
143
+ assert_equal(7, boxes[1].instance_variable_get(:@items).length)
144
+ end
145
+ end
128
146
  end
129
147
 
130
148
  describe "draw" do
@@ -419,6 +419,10 @@ describe HexaPDF::Layout::TextLayouter do
419
419
  assert(result.remaining_items.empty?)
420
420
  assert_equal(:success, result.status)
421
421
  end
422
+
423
+ result = @layouter.fit(boxes([20, 20], [20, 20], [20, 20], [20, 20]), 60, 200,
424
+ apply_first_text_indent: false)
425
+ assert_equal([60, 20], result.lines.map(&:width))
422
426
  end
423
427
 
424
428
  it "fits using a limited height" do
@@ -188,8 +188,11 @@ describe HexaPDF::DictionaryFields do
188
188
  ["D:19981223-08'00'", [1998, 12, 23, 00, 00, 00, "-08:00"]],
189
189
  ["D:199812-08'00'", [1998, 12, 01, 00, 00, 00, "-08:00"]],
190
190
  ["D:1998-08'00'", [1998, 01, 01, 00, 00, 00, "-08:00"]],
191
+ ["D:19981223195210Z", [1998, 12, 23, 19, 52, 10, "+00:00"]],
192
+ ["D:19981223195210Z00", [1998, 12, 23, 19, 52, 10, "+00:00"]],
193
+ ["D:19981223195210Z00'00", [1998, 12, 23, 19, 52, 10, "+00:00"]],
191
194
  ["D:19981223195210-08", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
192
- ["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], # missing '
195
+ ["D:19981223195210-08'00", [1998, 12, 23, 19, 52, 10, "-08:00"]], # no trailing ', as per PDF 2.0
193
196
  ["D:19981223195210-54'00", [1998, 12, 23, 19, 52, 10, "-23:59:59"]], # TZ hour too large
194
197
  ["D:19981223195210+10'65", [1998, 12, 23, 19, 52, 10, "+11:05"]], # TZ min too large
195
198
  ["D:19982423195210-08'00'", [1998, 12, 23, 19, 52, 10, "-08:00"]], # months too large
@@ -240,6 +240,7 @@ describe HexaPDF::Document do
240
240
  assert_kind_of(@myclass2, @doc.wrap({Subtype: :Global, Test: "true"}))
241
241
  assert_kind_of(@myclass2, @doc.wrap({Type: :MyClass, S: :TheSecond}))
242
242
  assert_kind_of(@myclass, @doc.wrap({Type: :MyClass, Subtype: :TheThird}))
243
+ assert_kind_of(HexaPDF::Type::FontTrueType, @doc.wrap({Subtype: :TrueType, BaseFont: :Help}))
243
244
  end
244
245
 
245
246
  it "respects the given type/subtype arguments" do
@@ -12,6 +12,14 @@ describe HexaPDF::Filter do
12
12
  40.times { @str << [rand(2**32)].pack('N') }
13
13
  end
14
14
 
15
+ describe "source_from_proc" do
16
+ it "returns the whole string, once" do
17
+ fib = @obj.source_from_proc { @str }
18
+ assert_equal(@str, collector(fib))
19
+ assert_equal('', collector(fib))
20
+ end
21
+ end
22
+
15
23
  describe "source_from_string" do
16
24
  it "doesn't modify the given string" do
17
25
  str = @str.dup
@@ -40,6 +40,15 @@ describe HexaPDF::Importer do
40
40
  end
41
41
  end
42
42
 
43
+ describe "::copy" do
44
+ it "copies a complete object including references" do
45
+ obj1 = HexaPDF::Importer.copy(@dest, @obj)
46
+ obj2 = HexaPDF::Importer.copy(@dest, @obj)
47
+ refute_same(obj1, obj2)
48
+ refute_same(obj1[:ref], obj2[:ref])
49
+ end
50
+ end
51
+
43
52
  describe "import" do
44
53
  it "updates the associated document" do
45
54
  obj = @importer.import(@obj)
@@ -50,26 +50,37 @@ describe HexaPDF::Object do
50
50
  @doc = HexaPDF::Document.new
51
51
  end
52
52
 
53
- it "doesn't touch wrapped direct objects" do
53
+ it "makes values of wrapped direct objects also direct" do
54
54
  obj = HexaPDF::Object.new(5)
55
- assert_same(obj, HexaPDF::Object.make_direct(obj))
55
+ assert_same(obj, HexaPDF::Object.make_direct(obj, @doc))
56
+ obj = HexaPDF::Dictionary.new({a: 5, b: HexaPDF::Object.new(:a, oid: 3, document: @doc)})
57
+ assert_same(obj, HexaPDF::Object.make_direct(obj, @doc))
58
+ assert_equal(:a, obj[:b])
56
59
  end
57
60
 
58
61
  it "works for simple values" do
59
62
  obj = HexaPDF::Object.new(5, oid: 1, document: @doc)
60
- assert_same(5, HexaPDF::Object.make_direct(obj))
63
+ assert_same(5, HexaPDF::Object.make_direct(obj, @doc))
61
64
  end
62
65
 
63
66
  it "works for hashes" do
64
67
  obj = HexaPDF::Dictionary.new({a: 5, b: HexaPDF::Object.new(:a, oid: 3, document: @doc)},
65
68
  oid: 1, document: @doc)
66
- assert_equal({a: 5, b: :a}, HexaPDF::Object.make_direct(obj))
69
+ assert_equal({a: 5, b: :a}, HexaPDF::Object.make_direct(obj, @doc))
67
70
  end
68
71
 
69
72
  it "works for arrays" do
70
73
  obj = HexaPDF::PDFArray.new([:b, HexaPDF::Object.new(:a, oid: 3, document: @doc)],
71
74
  oid: 1, document: @doc)
72
- assert_equal([:b, :a], HexaPDF::Object.make_direct(obj))
75
+ assert_equal([:b, :a], HexaPDF::Object.make_direct(obj, @doc))
76
+ end
77
+
78
+ it "resolves references" do
79
+ @doc.add(:Test, oid: 1)
80
+ obj = HexaPDF::PDFArray.new([HexaPDF::Reference.new(1, 0)],
81
+ oid: 2, document: @doc)
82
+ assert_equal([:Test], HexaPDF::Object.make_direct(obj, @doc))
83
+ assert(@doc.object(1).null?)
73
84
  end
74
85
  end
75
86
 
@@ -609,7 +609,7 @@ describe HexaPDF::Parser do
609
609
  end
610
610
 
611
611
  it "serially parses the contents" do
612
- create_parser("1 0 obj\n5\nendobj\n1 0 obj\n6\nendobj\ntrailer\n<</Size 1>>")
612
+ create_parser("1 0 obj\n5 endobj\n1 0 obj\n6\nendobj\ntrailer\n<</Size 1>>")
613
613
  assert_equal(6, @parser.load_object(@xref).value)
614
614
  end
615
615
 
@@ -31,6 +31,13 @@ describe HexaPDF::StreamData do
31
31
  end
32
32
 
33
33
  describe "fiber" do
34
+ it "returns a duplicate for a FiberDoubleForString source" do
35
+ source = HexaPDF::Filter.source_from_string("str")
36
+ fiber = HexaPDF::StreamData.new(source).fiber
37
+ assert_equal("str", fiber.resume)
38
+ refute_same(source, fiber)
39
+ end
40
+
34
41
  it "returns a fiber for a Proc source" do
35
42
  s = HexaPDF::StreamData.new(proc { :source })
36
43
  assert_equal(:source, s.fiber.resume)
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
40
40
  219
41
41
  %%EOF
42
42
  3 0 obj
43
- <</Producer(HexaPDF version 0.32.1)>>
43
+ <</Producer(HexaPDF version 0.33.0)>>
44
44
  endobj
45
45
  xref
46
46
  3 1
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
72
72
  141
73
73
  %%EOF
74
74
  6 0 obj
75
- <</Producer(HexaPDF version 0.32.1)>>
75
+ <</Producer(HexaPDF version 0.33.0)>>
76
76
  endobj
77
77
  2 0 obj
78
78
  <</Length 10>>stream
@@ -214,7 +214,7 @@ describe HexaPDF::Writer do
214
214
  <</Type/Page/MediaBox[0 0 595 842]/Parent 2 0 R/Resources<<>>>>
215
215
  endobj
216
216
  5 0 obj
217
- <</Producer(HexaPDF version 0.32.1)>>
217
+ <</Producer(HexaPDF version 0.33.0)>>
218
218
  endobj
219
219
  4 0 obj
220
220
  <</Root 1 0 R/Info 5 0 R/Size 6/Type/XRef/W[1 1 2]/Index[0 6]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 33>>stream
@@ -467,12 +467,20 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
467
467
  it "calculates the font size based on the rectangle height and border width" do
468
468
  @generator.create_appearances
469
469
  assert_operators(@widget[:AP][:N].stream,
470
- [:set_font_and_size, [:F1, 12.923875]],
470
+ [:set_font_and_size, [:F1, 13.235294]],
471
471
  range: 5)
472
472
  @widget.border_style(width: 2, color: :transparent)
473
473
  @generator.create_appearances
474
474
  assert_operators(@widget[:AP][:N].stream,
475
- [:set_font_and_size, [:F1, 11.487889]],
475
+ [:set_font_and_size, [:F1, 11.764706]],
476
+ range: 5)
477
+ end
478
+
479
+ it "shrinks the font size if necessary to fit the rectangle width" do
480
+ @field.field_value = "This is some arbitrary, long text"
481
+ @generator.create_appearances
482
+ assert_operators(@widget[:AP][:N].stream,
483
+ [:set_font_and_size, [:F1, 6.909955]],
476
484
  range: 5)
477
485
  end
478
486
 
@@ -573,7 +581,7 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
573
581
  assert_format("2, 3, #{style}, 0, \"E\", true",
574
582
  [[:set_device_rgb_non_stroking_color, [style % 2, 0.0, 0.0]],
575
583
  [:begin_text],
576
- [:set_text_matrix, [1, 0, 0, 1, 2, 3.240724]],
584
+ [:set_text_matrix, [1, 0, 0, 1, 2, 3.183272]],
577
585
  [:show_text, [result]]], 6..9)
578
586
  end
579
587
  end
@@ -598,10 +606,10 @@ describe HexaPDF::Type::AcroForm::AppearanceGenerator do
598
606
  [:append_rectangle, [1, 1, 98, 9.25]],
599
607
  [:clip_path_non_zero],
600
608
  [:end_path],
601
- [:set_font_and_size, [:F1, 6.641436]],
609
+ [:set_font_and_size, [:F1, 6.801471]],
602
610
  [:set_device_rgb_non_stroking_color, [1.0, 0.0, 0.0]],
603
611
  [:begin_text],
604
- [:set_text_matrix, [1, 0, 0, 1, 2, 3.240724]],
612
+ [:set_text_matrix, [1, 0, 0, 1, 2, 3.183272]],
605
613
  [:show_text, ["Text"]],
606
614
  [:end_text],
607
615
  [:restore_graphics_state],
@@ -42,11 +42,12 @@ describe HexaPDF::Type::AcroForm::Form do
42
42
  end
43
43
 
44
44
  it "finds the root fields" do
45
- @doc.pages.add[:Annots] = [{FT: :Tx}, {FT: :Tx2, Parent: {FT: :Tx3}}]
46
- @doc.pages.add[:Annots] = [{Subtype: :Widget}]
45
+ @doc.pages.add[:Annots] = [{Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx},
46
+ {Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx, Parent: {FT: :Tx}}]
47
+ @doc.pages.add[:Annots] = [{Subtype: :Widget, Rect: [0, 0, 0, 0]}]
47
48
  @doc.pages.add
48
49
 
49
- result = [{FT: :Tx}, {FT: :Tx3}]
50
+ result = [{Subtype: :Widget, Rect: [0, 0, 0, 0], FT: :Tx}, {FT: :Tx}]
50
51
  root_fields = @acro_form.find_root_fields
51
52
  assert_equal(result, root_fields.map(&:value))
52
53
  assert_kind_of(HexaPDF::Type::AcroForm::TextField, root_fields[0])
@@ -23,9 +23,14 @@ describe HexaPDF::Type::ObjectStream do
23
23
  before do
24
24
  @doc = Object.new
25
25
  @doc.instance_variable_set(:@version, '1.5')
26
- def (@doc).trailer
27
- @trailer ||= {Encrypt: HexaPDF::Object.new({}, oid: 9)}
26
+ @doc.define_singleton_method(:revisions) do
27
+ rev1 = Object.new
28
+ def rev1.trailer; {Encrypt: HexaPDF::Object.new({}, oid: 10)}; end
29
+ rev2 = Object.new
30
+ def rev2.trailer; {Encrypt: HexaPDF::Object.new({}, oid: 9)}; end
31
+ @revisions ||= [rev1, rev2]
28
32
  end
33
+ @doc.define_singleton_method(:trailer) { revisions.last.trailer }
29
34
  @obj = HexaPDF::Type::ObjectStream.new({N: 2, First: 8}, oid: 1, document: @doc,
30
35
  stream: "1 0 5 2 5 [1 2]")
31
36
  end
@@ -96,8 +101,9 @@ describe HexaPDF::Type::ObjectStream do
96
101
  assert_equal("", @obj.stream)
97
102
  end
98
103
 
99
- it "doesn't allow the encryption dictionary to be compressed" do
104
+ it "doesn't allow an encryption dictionary to be compressed" do
100
105
  @obj.add_object(@doc.trailer[:Encrypt])
106
+ @obj.add_object(@doc.revisions[0].trailer[:Encrypt])
101
107
  @obj.write_objects(@revision)
102
108
  assert_equal(0, @obj.value[:N])
103
109
  assert_equal(0, @obj.value[:First])
@@ -557,7 +557,7 @@ describe HexaPDF::Type::Page do
557
557
  @page = @doc.pages.add
558
558
  @appearance = @doc.add({Type: :XObject, Subtype: :Form, BBox: [-10, -5, 50, 20]}, stream: "")
559
559
  @annot1 = @doc.add({Type: :Annot, Subtype: :Text, Rect: [100, 100, 160, 125], AP: {N: @appearance}})
560
- @annot2 = @doc.add({Rect: [10, 10, 70, 35], AP: {N: @appearance}})
560
+ @annot2 = @doc.add({Type: :Annot, Subtype: :Text, Rect: [10, 10, 70, 35], AP: {N: @appearance}})
561
561
  @page[:Annots] = [@annot1, @annot2]
562
562
  @canvas = @page.canvas(type: :overlay)
563
563
  end
@@ -591,6 +591,18 @@ describe HexaPDF::Type::Page do
591
591
  assert(@annot2.null?)
592
592
  end
593
593
 
594
+ it "gracefully handles invalid /Annot key values" do
595
+ @page[:Annots] << nil << @doc.add({}, stream: '')
596
+ result = @page.flatten_annotations
597
+ assert(result.empty?)
598
+ assert(@annot1.null?)
599
+ assert(@annot2.null?)
600
+
601
+ @page[:Annots] = @doc.add({}, stream: '')
602
+ result = @page.flatten_annotations
603
+ assert(result.empty?)
604
+ end
605
+
594
606
  it "only deletes the widget annotation of a form field even if it is embedded in the field object" do
595
607
  form = @doc.acro_form(create: true)
596
608
  field = form.create_text_field('test')
@@ -631,7 +643,7 @@ describe HexaPDF::Type::Page do
631
643
  [:restore_graphics_state]])
632
644
  end
633
645
 
634
- it "ignores annotations without appearane stream" do
646
+ it "ignores annotations without appearance stream" do
635
647
  @annot1.delete(:AP)
636
648
  result = @page.flatten_annotations
637
649
  assert_equal([@annot1], result)
@@ -708,10 +720,12 @@ describe HexaPDF::Type::Page do
708
720
  it "yields each annotation" do
709
721
  page = @doc.pages.add
710
722
  annot1 = @doc.add({Type: :Annot, Subtype: :Text, Rect: [100, 100, 160, 125]})
711
- annot2 = @doc.add({Rect: [10, 10, 70, 35]})
712
- page[:Annots] = [annot1, nil, annot2]
723
+ annot2 = @doc.add({Subtype: :Unknown, Rect: [10, 10, 70, 35]})
724
+ not_an_annot = @doc.add({}, stream: '')
725
+ page[:Annots] = [not_an_annot, annot1, nil, annot2]
713
726
 
714
727
  annotations = page.each_annotation.to_a
728
+ assert_equal(2, annotations.size)
715
729
  assert_equal([100, 100, 160, 125], annotations[0][:Rect])
716
730
  assert_equal(:Annot, annotations[0].type)
717
731
  assert_equal(:Annot, annotations[1].type)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hexapdf
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.32.1
4
+ version: 0.33.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Leitner
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-20 00:00:00.000000000 Z
11
+ date: 2023-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cmdparse
@@ -36,14 +36,20 @@ dependencies:
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.3'
39
+ version: '0.4'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.4.1
40
43
  type: :runtime
41
44
  prerelease: false
42
45
  version_requirements: !ruby/object:Gem::Requirement
43
46
  requirements:
44
47
  - - "~>"
45
48
  - !ruby/object:Gem::Version
46
- version: '0.3'
49
+ version: '0.4'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.4.1
47
53
  - !ruby/object:Gem::Dependency
48
54
  name: openssl
49
55
  requirement: !ruby/object:Gem::Requirement
@@ -292,6 +298,7 @@ files:
292
298
  - examples/022-outline.rb
293
299
  - examples/023-images.rb
294
300
  - examples/024-digital-signatures.rb
301
+ - examples/025-table_box.rb
295
302
  - examples/emoji-smile.png
296
303
  - examples/emoji-wink.png
297
304
  - examples/machupicchu.jpg
@@ -430,6 +437,7 @@ files:
430
437
  - lib/hexapdf/layout/numeric_refinements.rb
431
438
  - lib/hexapdf/layout/page_style.rb
432
439
  - lib/hexapdf/layout/style.rb
440
+ - lib/hexapdf/layout/table_box.rb
433
441
  - lib/hexapdf/layout/text_box.rb
434
442
  - lib/hexapdf/layout/text_fragment.rb
435
443
  - lib/hexapdf/layout/text_layouter.rb
@@ -682,6 +690,7 @@ files:
682
690
  - test/hexapdf/layout/test_list_box.rb
683
691
  - test/hexapdf/layout/test_page_style.rb
684
692
  - test/hexapdf/layout/test_style.rb
693
+ - test/hexapdf/layout/test_table_box.rb
685
694
  - test/hexapdf/layout/test_text_box.rb
686
695
  - test/hexapdf/layout/test_text_fragment.rb
687
696
  - test/hexapdf/layout/test_text_layouter.rb
@@ -760,7 +769,7 @@ licenses:
760
769
  - AGPL-3.0
761
770
  - Nonstandard
762
771
  metadata: {}
763
- post_install_message:
772
+ post_install_message:
764
773
  rdoc_options: []
765
774
  require_paths:
766
775
  - lib
@@ -775,8 +784,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
775
784
  - !ruby/object:Gem::Version
776
785
  version: '0'
777
786
  requirements: []
778
- rubygems_version: 3.4.1
779
- signing_key:
787
+ rubygems_version: 3.5.0.dev
788
+ signing_key:
780
789
  specification_version: 4
781
790
  summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
782
791
  test_files: []