hexapdf 0.32.2 → 0.34.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -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/examples/026-optional_content.rb +55 -0
  19. data/examples/027-composer_optional_content.rb +83 -0
  20. data/lib/hexapdf/cli/command.rb +12 -3
  21. data/lib/hexapdf/cli/fonts.rb +1 -1
  22. data/lib/hexapdf/cli/form.rb +5 -5
  23. data/lib/hexapdf/cli/inspect.rb +5 -7
  24. data/lib/hexapdf/composer.rb +106 -53
  25. data/lib/hexapdf/configuration.rb +65 -40
  26. data/lib/hexapdf/content/canvas.rb +445 -267
  27. data/lib/hexapdf/content/color_space.rb +72 -25
  28. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  31. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  32. data/lib/hexapdf/content/graphic_object.rb +6 -7
  33. data/lib/hexapdf/content/graphics_state.rb +54 -45
  34. data/lib/hexapdf/content/operator.rb +54 -54
  35. data/lib/hexapdf/content/parser.rb +2 -2
  36. data/lib/hexapdf/content/processor.rb +15 -15
  37. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  38. data/lib/hexapdf/content.rb +5 -0
  39. data/lib/hexapdf/dictionary.rb +7 -5
  40. data/lib/hexapdf/dictionary_fields.rb +43 -16
  41. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  42. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  43. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  44. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  45. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  46. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  47. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  48. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  49. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  50. data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
  51. data/lib/hexapdf/digital_signature.rb +7 -2
  52. data/lib/hexapdf/document/destinations.rb +12 -11
  53. data/lib/hexapdf/document/files.rb +1 -1
  54. data/lib/hexapdf/document/fonts.rb +1 -1
  55. data/lib/hexapdf/document/layout.rb +170 -39
  56. data/lib/hexapdf/document/pages.rb +4 -3
  57. data/lib/hexapdf/document.rb +96 -55
  58. data/lib/hexapdf/encryption/aes.rb +5 -5
  59. data/lib/hexapdf/encryption/arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  61. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/identity.rb +1 -1
  63. data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
  64. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  65. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  66. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  67. data/lib/hexapdf/encryption.rb +7 -2
  68. data/lib/hexapdf/error.rb +18 -0
  69. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  70. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  71. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  72. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  73. data/lib/hexapdf/filter/pass_through.rb +1 -1
  74. data/lib/hexapdf/filter/predictor.rb +1 -1
  75. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  76. data/lib/hexapdf/filter.rb +55 -6
  77. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  78. data/lib/hexapdf/font/cmap.rb +1 -1
  79. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  82. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  83. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  84. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  85. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  86. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  87. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  88. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  89. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  90. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  91. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  92. data/lib/hexapdf/font_loader.rb +3 -0
  93. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  94. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  95. data/lib/hexapdf/image_loader/png.rb +2 -2
  96. data/lib/hexapdf/image_loader.rb +1 -1
  97. data/lib/hexapdf/importer.rb +13 -0
  98. data/lib/hexapdf/layout/box.rb +32 -5
  99. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  100. data/lib/hexapdf/layout/column_box.rb +20 -5
  101. data/lib/hexapdf/layout/frame.rb +53 -18
  102. data/lib/hexapdf/layout/image_box.rb +5 -0
  103. data/lib/hexapdf/layout/inline_box.rb +21 -9
  104. data/lib/hexapdf/layout/list_box.rb +50 -20
  105. data/lib/hexapdf/layout/page_style.rb +6 -5
  106. data/lib/hexapdf/layout/style.rb +64 -9
  107. data/lib/hexapdf/layout/table_box.rb +684 -0
  108. data/lib/hexapdf/layout/text_box.rb +12 -3
  109. data/lib/hexapdf/layout/text_fragment.rb +29 -3
  110. data/lib/hexapdf/layout/text_layouter.rb +32 -8
  111. data/lib/hexapdf/layout.rb +1 -0
  112. data/lib/hexapdf/name_tree_node.rb +1 -1
  113. data/lib/hexapdf/number_tree_node.rb +1 -1
  114. data/lib/hexapdf/object.rb +18 -7
  115. data/lib/hexapdf/parser.rb +7 -7
  116. data/lib/hexapdf/pdf_array.rb +1 -1
  117. data/lib/hexapdf/rectangle.rb +1 -1
  118. data/lib/hexapdf/reference.rb +1 -1
  119. data/lib/hexapdf/revision.rb +1 -1
  120. data/lib/hexapdf/revisions.rb +3 -3
  121. data/lib/hexapdf/serializer.rb +15 -15
  122. data/lib/hexapdf/stream.rb +5 -4
  123. data/lib/hexapdf/tokenizer.rb +14 -14
  124. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  125. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  128. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  130. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  131. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  132. data/lib/hexapdf/type/acro_form.rb +1 -1
  133. data/lib/hexapdf/type/action.rb +1 -1
  134. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  135. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  136. data/lib/hexapdf/type/actions/launch.rb +1 -1
  137. data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
  138. data/lib/hexapdf/type/actions/uri.rb +1 -1
  139. data/lib/hexapdf/type/actions.rb +2 -1
  140. data/lib/hexapdf/type/annotation.rb +3 -3
  141. data/lib/hexapdf/type/annotations/link.rb +1 -1
  142. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  143. data/lib/hexapdf/type/annotations/text.rb +2 -3
  144. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  145. data/lib/hexapdf/type/annotations.rb +1 -1
  146. data/lib/hexapdf/type/catalog.rb +11 -2
  147. data/lib/hexapdf/type/cid_font.rb +18 -4
  148. data/lib/hexapdf/type/embedded_file.rb +1 -1
  149. data/lib/hexapdf/type/file_specification.rb +2 -2
  150. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  151. data/lib/hexapdf/type/font_simple.rb +2 -2
  152. data/lib/hexapdf/type/font_type0.rb +3 -3
  153. data/lib/hexapdf/type/font_type3.rb +1 -1
  154. data/lib/hexapdf/type/form.rb +76 -6
  155. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  156. data/lib/hexapdf/type/icon_fit.rb +1 -1
  157. data/lib/hexapdf/type/image.rb +1 -1
  158. data/lib/hexapdf/type/info.rb +1 -1
  159. data/lib/hexapdf/type/mark_information.rb +1 -1
  160. data/lib/hexapdf/type/names.rb +2 -2
  161. data/lib/hexapdf/type/object_stream.rb +2 -1
  162. data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
  163. data/lib/hexapdf/type/optional_content_group.rb +370 -0
  164. data/lib/hexapdf/type/optional_content_membership.rb +63 -0
  165. data/lib/hexapdf/type/optional_content_properties.rb +158 -0
  166. data/lib/hexapdf/type/outline.rb +1 -1
  167. data/lib/hexapdf/type/outline_item.rb +1 -1
  168. data/lib/hexapdf/type/page.rb +46 -21
  169. data/lib/hexapdf/type/page_label.rb +5 -9
  170. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  171. data/lib/hexapdf/type/resources.rb +1 -1
  172. data/lib/hexapdf/type/trailer.rb +2 -2
  173. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  174. data/lib/hexapdf/type/xref_stream.rb +2 -2
  175. data/lib/hexapdf/type.rb +4 -0
  176. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
  177. data/lib/hexapdf/version.rb +1 -1
  178. data/lib/hexapdf/writer.rb +4 -4
  179. data/lib/hexapdf/xref_section.rb +2 -2
  180. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  181. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  182. data/test/hexapdf/content/test_canvas.rb +49 -1
  183. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  184. data/test/hexapdf/document/test_files.rb +2 -2
  185. data/test/hexapdf/document/test_layout.rb +105 -2
  186. data/test/hexapdf/document/test_pages.rb +6 -6
  187. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  188. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  189. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  190. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  191. data/test/hexapdf/layout/test_box.rb +14 -5
  192. data/test/hexapdf/layout/test_column_box.rb +65 -21
  193. data/test/hexapdf/layout/test_frame.rb +27 -15
  194. data/test/hexapdf/layout/test_image_box.rb +4 -0
  195. data/test/hexapdf/layout/test_inline_box.rb +17 -3
  196. data/test/hexapdf/layout/test_list_box.rb +84 -33
  197. data/test/hexapdf/layout/test_page_style.rb +3 -2
  198. data/test/hexapdf/layout/test_style.rb +60 -0
  199. data/test/hexapdf/layout/test_table_box.rb +728 -0
  200. data/test/hexapdf/layout/test_text_box.rb +26 -0
  201. data/test/hexapdf/layout/test_text_fragment.rb +33 -0
  202. data/test/hexapdf/layout/test_text_layouter.rb +36 -5
  203. data/test/hexapdf/test_composer.rb +10 -0
  204. data/test/hexapdf/test_dictionary.rb +10 -0
  205. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  206. data/test/hexapdf/test_document.rb +5 -0
  207. data/test/hexapdf/test_filter.rb +8 -0
  208. data/test/hexapdf/test_importer.rb +9 -0
  209. data/test/hexapdf/test_object.rb +16 -5
  210. data/test/hexapdf/test_stream.rb +7 -0
  211. data/test/hexapdf/test_writer.rb +3 -3
  212. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  213. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  214. data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
  215. data/test/hexapdf/type/test_catalog.rb +11 -0
  216. data/test/hexapdf/type/test_form.rb +119 -0
  217. data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
  218. data/test/hexapdf/type/test_optional_content_group.rb +158 -0
  219. data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
  220. data/test/hexapdf/type/test_page.rb +20 -6
  221. metadata +28 -8
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # Tokenizes the content of an IO object following the PDF rules.
44
44
  #
45
- # See: PDF1.7 s7.2
45
+ # See: PDF2.0 s7.2
46
46
  class Tokenizer
47
47
 
48
48
  # Represents a keyword in a PDF file.
@@ -61,12 +61,12 @@ module HexaPDF
61
61
 
62
62
  # Characters defined as whitespace.
63
63
  #
64
- # See: PDF1.7 s7.2.2
64
+ # See: PDF2.0 s7.2.2
65
65
  WHITESPACE = " \n\r\0\t\f"
66
66
 
67
67
  # Characters defined as delimiters.
68
68
  #
69
- # See: PDF1.7 s7.2.2
69
+ # See: PDF2.0 s7.2.2
70
70
  DELIMITER = "()<>{}/[]%"
71
71
 
72
72
  WHITESPACE_MULTI_RE = /[#{WHITESPACE}]+/ # :nodoc:
@@ -171,7 +171,7 @@ module HexaPDF
171
171
  # If the +allow_end_array_token+ argument is +true+, the ']' token is permitted to facilitate
172
172
  # the use of this method during array parsing.
173
173
  #
174
- # See: PDF1.7 s7.3
174
+ # See: PDF2.0 s7.3
175
175
  def next_object(allow_end_array_token: false, allow_keyword: false)
176
176
  token = next_token
177
177
 
@@ -231,7 +231,7 @@ module HexaPDF
231
231
  # If a problem is detected, yields to caller where the argument +recoverable+ is truthy if the
232
232
  # problem is recoverable.
233
233
  #
234
- # See: PDF1.7 7.5.4
234
+ # See: PDF2.0 7.5.4
235
235
  def next_xref_entry #:yield: recoverable
236
236
  prepare_string_scanner(20)
237
237
  if !@ss.skip(/(\d{10}) (\d{5}) ([nf])(?: \r| \n|\r\n|(\r\r|\r|\n))/) || @ss[4]
@@ -242,7 +242,7 @@ module HexaPDF
242
242
 
243
243
  # Skips all whitespace at the current position.
244
244
  #
245
- # See: PDF1.7 s7.2.2
245
+ # See: PDF2.0 s7.2.2
246
246
  def skip_whitespace
247
247
  prepare_string_scanner
248
248
  prepare_string_scanner while @ss.skip(WHITESPACE_MULTI_RE)
@@ -268,7 +268,7 @@ module HexaPDF
268
268
 
269
269
  # Parses the keyword at the current position.
270
270
  #
271
- # See: PDF1.7 s7.2
271
+ # See: PDF2.0 s7.2
272
272
  def parse_keyword
273
273
  str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
274
274
  TOKEN_CACHE[str]
@@ -278,12 +278,12 @@ module HexaPDF
278
278
 
279
279
  # Parses the number (integer or real) at the current position.
280
280
  #
281
- # See: PDF1.7 s7.3.3
281
+ # See: PDF2.0 s7.3.3
282
282
  def parse_number
283
283
  val = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
284
284
  if val.match?(/\A[+-]?\d++(?!\.)\z/)
285
285
  tmp = val.to_i
286
- # Handle object references, see PDF1.7 s7.3.10
286
+ # Handle object references, see PDF2.0 s7.3.10
287
287
  prepare_string_scanner(10)
288
288
  if @ss.scan(REFERENCE_RE)
289
289
  tmp = if tmp > 0
@@ -315,7 +315,7 @@ module HexaPDF
315
315
 
316
316
  # Parses the literal string at the current position.
317
317
  #
318
- # See: PDF1.7 s7.3.4.2
318
+ # See: PDF2.0 s7.3.4.2
319
319
  def parse_literal_string
320
320
  @ss.pos += 1
321
321
  str = "".b
@@ -358,7 +358,7 @@ module HexaPDF
358
358
 
359
359
  # Parses the hex string at the current position.
360
360
  #
361
- # See: PDF1.7 s7.3.4.3
361
+ # See: PDF2.0 s7.3.4.3
362
362
  def parse_hex_string
363
363
  @ss.pos += 1
364
364
  data = scan_until(/(?=>)/)
@@ -373,7 +373,7 @@ module HexaPDF
373
373
 
374
374
  # Parses the name at the current position.
375
375
  #
376
- # See: PDF1.7 s7.3.5
376
+ # See: PDF2.0 s7.3.5
377
377
  def parse_name
378
378
  @ss.pos += 1
379
379
  str = scan_until(WHITESPACE_OR_DELIMITER_RE) || @ss.scan(/.*/)
@@ -389,7 +389,7 @@ module HexaPDF
389
389
  #
390
390
  # It is assumed that the initial '[' has already been scanned.
391
391
  #
392
- # See: PDF1.7 s7.3.6
392
+ # See: PDF2.0 s7.3.6
393
393
  def parse_array
394
394
  result = []
395
395
  while true
@@ -408,7 +408,7 @@ module HexaPDF
408
408
  #
409
409
  # It is assumed that the initial '<<' has already been scanned.
410
410
  #
411
- # See: PDF1.7 s7.3.7
411
+ # See: PDF2.0 s7.3.7
412
412
  def parse_dictionary
413
413
  result = {}
414
414
  while true
@@ -61,7 +61,7 @@ module HexaPDF
61
61
  # By subclassing and overriding the necessary methods it is possible to define custom
62
62
  # appearances.
63
63
  #
64
- # See: PDF1.7 s12.5.5, s12.7
64
+ # See: PDF2.0 s12.5.5, s12.7
65
65
  class AppearanceGenerator
66
66
 
67
67
  # Creates a new instance for the given +widget+.
@@ -200,7 +200,7 @@ module HexaPDF
200
200
  def create_text_appearances
201
201
  default_resources = @document.acro_form.default_resources
202
202
  font, font_size, font_color = retrieve_font_information(default_resources)
203
- style = HexaPDF::Layout::Style.new(font: font, fill_color: font_color)
203
+ style = HexaPDF::Layout::Style.new(font: font, font_size: font_size, fill_color: font_color)
204
204
  border_style = @widget.border_style
205
205
  padding = [1, border_style.width].max
206
206
 
@@ -226,8 +226,6 @@ module HexaPDF
226
226
 
227
227
  canvas = form.canvas
228
228
  apply_background_and_border(border_style, canvas)
229
- style.font_size = calculate_font_size(font, font_size, height, border_style)
230
- style.clear_cache
231
229
 
232
230
  canvas.marked_content_sequence(:Tx) do
233
231
  if @field.field_value || @field.concrete_field_type == :list_box
@@ -362,6 +360,7 @@ module HexaPDF
362
360
  def draw_single_line_text(canvas, width, height, style, padding)
363
361
  value, text_color = apply_javascript_formatting(@field.field_value)
364
362
  style.fill_color = text_color if text_color
363
+ calculate_and_apply_font_size(value, style, width, height, padding)
365
364
  fragment = HexaPDF::Layout::TextFragment.create(value, style)
366
365
 
367
366
  if @field.concrete_field_type == :comb_text_field
@@ -431,6 +430,11 @@ module HexaPDF
431
430
 
432
431
  # Draws the visible option items of the list box in the widget's rectangle.
433
432
  def draw_list_box(canvas, width, height, style, padding)
433
+ if style.font_size == 0
434
+ style.font_size = 12 # Seems to be Adobe's default
435
+ style.clear_cache
436
+ end
437
+
434
438
  option_items = @field.option_items
435
439
  top_index = @field.list_box_top_index
436
440
  items = [Layout::TextFragment.create(option_items[top_index..-1].join("\n"), style)]
@@ -475,24 +479,20 @@ module HexaPDF
475
479
  [font, font_size, font_color]
476
480
  end
477
481
 
478
- # Calculates the font size for text fields based on the font and font size of the default
479
- # appearance string, the annotation rectangle's height and the border style.
480
- def calculate_font_size(font, font_size, height, border_style)
481
- if font_size == 0
482
- case @field.concrete_field_type
483
- when :multiline_text_field
484
- 0 # Handled by multiline drawing code
485
- when :list_box
486
- 12 # Seems to be Adobe's default
487
- else
488
- unit_font_size = (font.wrapped_font.bounding_box[3] - font.wrapped_font.bounding_box[1]) *
489
- font.scaling_factor / 1000.0
490
- # The constant factor was found empirically by checking what Adobe Reader etc. do
491
- (height - 2 * border_style.width) / unit_font_size * 0.83
492
- end
493
- else
494
- font_size
495
- end
482
+ # Calculates the font size for single line text fields using auto-sizing, based on the font
483
+ # and font size of the default appearance string, the annotation rectangle's height and
484
+ # width and the given padding. The font size is then applied to the provided style object.
485
+ def calculate_and_apply_font_size(value, style, width, height, padding)
486
+ return if style.font_size != 0
487
+
488
+ font = style.font
489
+ unit_font_size = (font.wrapped_font.bounding_box[3] - font.wrapped_font.bounding_box[1]) *
490
+ font.scaling_factor / 1000.0
491
+ # The constant factor was found empirically by checking what Adobe Reader etc. do
492
+ style.font_size = (height - 2 * padding) / unit_font_size * 0.85
493
+ fragment = HexaPDF::Layout::TextFragment.create(value, style)
494
+ style.font_size = [style.font_size, style.font_size * (width - 4 * padding) / fragment.width].min
495
+ style.clear_cache
496
496
  end
497
497
 
498
498
  # Handles Javascript formatting routines for single-line text fields.
@@ -81,7 +81,7 @@ module HexaPDF
81
81
  # :radios_in_unison:: A group of radio buttons with the same value for the on state will turn
82
82
  # on or off in unison.
83
83
  #
84
- # See: PDF1.7 s12.7.4.2
84
+ # See: PDF2.0 s12.7.4.2
85
85
  class ButtonField < Field
86
86
 
87
87
  define_type :XXAcroFormField
@@ -66,7 +66,7 @@ module HexaPDF
66
66
  # :commit_on_sel_change:: If set, a new value should be commited as soon as a selection is
67
67
  # made.
68
68
  #
69
- # See: PDF1.7 s12.7.4.4
69
+ # See: PDF2.0 s12.7.5.4
70
70
  class ChoiceField < VariableTextField
71
71
 
72
72
  define_type :XXAcroFormField
@@ -86,7 +86,7 @@ module HexaPDF
86
86
  # to combination of the superclass value of the constant and the mapping of flag names to bit
87
87
  # indices.
88
88
  #
89
- # See: PDF1.7 s12.7.3.1
89
+ # See: PDF2.0 s12.7.4.1
90
90
  class Field < Dictionary
91
91
 
92
92
  # Provides a #value method for hash that returns self so that a Hash can be used
@@ -367,7 +367,7 @@ module HexaPDF
367
367
  document.pages.each do |page|
368
368
  if page.key?(:Annots) && (index = page[:Annots].index(self))
369
369
  page[:Annots][index] = widget
370
- break # Each annotation dictionary may only appear on one page, see PDF1.7 12.5.2
370
+ break # Each annotation dictionary may only appear on one page, see PDF2.0 12.5.2
371
371
  end
372
372
  end
373
373
  widget
@@ -68,7 +68,7 @@ module HexaPDF
68
68
  # HexaPDF uses the configuration option +acro_form.create_appearance_streams+ to determine
69
69
  # whether appearances should automatically be generated.
70
70
  #
71
- # See: PDF1.7 s12.7.2, Field, HexaPDF::Type::Annotations::Widget
71
+ # See: PDF2.0 s12.7.3, Field, HexaPDF::Type::Annotations::Widget
72
72
  class Form < Dictionary
73
73
 
74
74
  extend Utils::BitField
@@ -49,13 +49,13 @@ module HexaPDF
49
49
  # If the signature should not be visible, the associated widget annotation should have zero
50
50
  # width and height; and/or the 'hidden' or 'no_view' flags of the annotation should be set.
51
51
  #
52
- # See: PDF1.7 s12.7.4.5
52
+ # See: PDF2.0 s12.7.5.5
53
53
  class SignatureField < Field
54
54
 
55
55
  # A signature field lock dictionary specifies a set of form fields that should be locked
56
56
  # once the associated signature field is signed.
57
57
  #
58
- # See: PDF1.7 s12.7.4.5
58
+ # See: PDF2.0 s12.7.5.5
59
59
  class LockDictionary < Dictionary
60
60
 
61
61
  define_type :SigFieldLock
@@ -86,7 +86,7 @@ module HexaPDF
86
86
  # The available flags are: filter, sub_filter, v, reasons, legal_attestation, add_rev_info
87
87
  # and digest_method.
88
88
  #
89
- # See: PDF1.7 s12.7.4.5
89
+ # See: PDF2.0 s12.7.5.5
90
90
  class SeedValueDictionary < Dictionary
91
91
 
92
92
  extend Utils::BitField
@@ -145,7 +145,7 @@ module HexaPDF
145
145
  #
146
146
  # The available flags are: subject, issuer, oid, subject_dn, reserved, key_usage and url.
147
147
  #
148
- # See: PDF1.7 s12.7.4.5
148
+ # See: PDF2.0 s12.7.5.5
149
149
  class CertificateSeedValueDictionary < Dictionary
150
150
 
151
151
  extend Utils::BitField
@@ -70,7 +70,7 @@ module HexaPDF
70
70
  #
71
71
  # :rich_text:: The field is a rich text field.
72
72
  #
73
- # See: PDF1.7 s12.7.4.3
73
+ # See: PDF2.0 s12.7.5.3
74
74
  class TextField < VariableTextField
75
75
 
76
76
  define_type :XXAcroFormField
@@ -48,7 +48,7 @@ module HexaPDF
48
48
  # value; the value is entered by the user and needs to be rendered correctly by the PDF
49
49
  # reader.
50
50
  #
51
- # See: PDF1.7 s12.7.3.3
51
+ # See: PDF2.0 s12.7.4.3
52
52
  class VariableTextField < Field
53
53
 
54
54
  define_field :DA, type: String
@@ -39,7 +39,7 @@ module HexaPDF
39
39
 
40
40
  # Namespace module for all AcroForm related dictionary types.
41
41
  #
42
- # See: PDF1.7 s12.7
42
+ # See: PDF2.0 s12.7
43
43
  module AcroForm
44
44
 
45
45
  autoload(:Form, 'hexapdf/type/acro_form/form')
@@ -44,7 +44,7 @@ module HexaPDF
44
44
  # Action dictionaries are used, for example, by annotations or outline items to specify the
45
45
  # action that should be performed. Each action class should be defined under the Actions module.
46
46
  #
47
- # See: PDF1.7 s12.6
47
+ # See: PDF2.0 s12.6
48
48
  class Action < Dictionary
49
49
 
50
50
  define_type :Action
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # A Go-To action changes the view to a specific destination.
44
44
  #
45
- # See: PDF1.7 s12.6.4.2
45
+ # See: PDF2.0 s12.6.4.2
46
46
  class GoTo < Action
47
47
 
48
48
  define_field :S, type: Symbol, required: true, default: :GoTo
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # A remote Go-To action dictionary jumps to a destination in a different PDF file.
44
44
  #
45
- # See: PDF1.7 s12.6.4.3
45
+ # See: PDF2.0 s12.6.4.3
46
46
  class GoToR < Action
47
47
 
48
48
  define_field :S, type: Symbol, required: true, default: :GoToR
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # A Launch action dictionary launches an application, opens a document or prints a document.
44
44
  #
45
- # See: PDF1.7 s12.6.4.5
45
+ # See: PDF2.0 s12.6.4.6
46
46
  class Launch < Action
47
47
 
48
48
  # The type used for the /Win field of a Launch action dictionary.
@@ -0,0 +1,86 @@
1
+ # -*- encoding: utf-8; frozen_string_literal: true -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2014-2023 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #
33
+ # If the GNU Affero General Public License doesn't fit your need,
34
+ # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
+ #++
36
+
37
+ require 'hexapdf/type/action'
38
+
39
+ module HexaPDF
40
+ module Type
41
+ module Actions
42
+
43
+ # A Set-OCG-state action changes the state of one or more optional content groups.
44
+ #
45
+ # See: PDF2.0 s12.6.4.13, HexaPDF::Type::OptionalContentGroup
46
+ class SetOCGState < Action
47
+
48
+ define_field :S, type: Symbol, required: true, default: :SetOCGState
49
+ define_field :State, type: PDFArray, required: true, default: []
50
+ define_field :PreserveRB, type: Boolean, default: true
51
+
52
+ STATE_TYPE_MAPPING = {on: :ON, ON: :ON, off: :OFF, OFF: :OFF, # :nodoc:
53
+ toggle: :Toggle, Toggle: :Toggle}
54
+
55
+ # Adds a state changing sequence to the /State array.
56
+ #
57
+ # The +type+ argument specifies how the state of the given optional content groups should be
58
+ # changed.
59
+ #
60
+ # +type+:: The type of sequence to add, either :on/:ON (for turning the OCGs on) , :off/:OFF
61
+ # (for turning the OCGs off), or :toggle/:Toggle (for toggling the state of the
62
+ # OCGs).
63
+ #
64
+ # +ocgs+:: A single optional content group or an array of optional content groups to which
65
+ # the state change defined with +type+ should be applied. The OCGs can be specified
66
+ # via their dictionary or by name which uses the first found OCG with that name.
67
+ def add_state_change(type, ocgs)
68
+ type = STATE_TYPE_MAPPING.fetch(type) do
69
+ raise ArgumentError, "Invalid type #{type} specified, should be one of :on, :off or :toggle"
70
+ end
71
+ state = self[:State]
72
+ state << type
73
+ Array(ocgs).each do |ocg|
74
+ if (ocg_name = ocg).kind_of?(String)
75
+ ocg = document.optional_content.ocg(ocg_name, create: false)
76
+ raise HexaPDF::Error, "Invalid OCG named '#{ocg_name}' specified" unless ocg
77
+ end
78
+ state << ocg
79
+ end
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+ end
86
+ end
@@ -42,7 +42,7 @@ module HexaPDF
42
42
 
43
43
  # Represents an URI action dictionary, mostly used for opening Internet pages.
44
44
  #
45
- # See: PDF1.7 s12.6.4.7
45
+ # See: PDF2.0 s12.6.4.8
46
46
  class URI < Action
47
47
 
48
48
  define_field :S, type: Symbol, required: true, default: :URI
@@ -41,13 +41,14 @@ module HexaPDF
41
41
 
42
42
  # Namespace module for all PDF action dictionary types.
43
43
  #
44
- # See: PDF1.7 s12.6.4, Action
44
+ # See: PDF2.0 s12.6.4, Action
45
45
  module Actions
46
46
 
47
47
  autoload(:GoTo, 'hexapdf/type/actions/go_to')
48
48
  autoload(:GoToR, 'hexapdf/type/actions/go_to_r')
49
49
  autoload(:Launch, 'hexapdf/type/actions/launch')
50
50
  autoload(:URI, 'hexapdf/type/actions/uri')
51
+ autoload(:SetOCGState, 'hexapdf/type/actions/set_ocg_state')
51
52
 
52
53
  end
53
54
 
@@ -43,7 +43,7 @@ module HexaPDF
43
43
  # Annotations are used to associate objects like notes, sounds or movies with a location on a
44
44
  # PDF page or allow the user to interact with a PDF document using a keyboard or mouse.
45
45
  #
46
- # See: PDF1.7 s12.5
46
+ # See: PDF2.0 s12.5
47
47
  class Annotation < Dictionary
48
48
 
49
49
  # The appearance dictionary references appearance streams for various use cases.
@@ -52,7 +52,7 @@ module HexaPDF
52
52
  # latter is used when the appearance depends on the state of the annotation, e.g. a check box
53
53
  # widget that can be checked or unchecked.
54
54
  #
55
- # See: PDF1.7 s12.5.5
55
+ # See: PDF2.0 s12.5.5
56
56
  class AppearanceDictionary < Dictionary
57
57
 
58
58
  define_type :XXAppearanceDictionary
@@ -101,7 +101,7 @@ module HexaPDF
101
101
 
102
102
  # Border style dictionary used by various annotation types.
103
103
  #
104
- # See: PDF1.7 s12.5.4
104
+ # See: PDF2.0 s12.5.4
105
105
  class Border < Dictionary
106
106
 
107
107
  define_type :Border
@@ -43,7 +43,7 @@ module HexaPDF
43
43
  # Link annotations represent a link to a destination elsewhere in the PDF document or an
44
44
  # action to be performed.
45
45
  #
46
- # See: PDF1.7 s12.5.6.5, HexaPDF::Type::Annotation
46
+ # See: PDF2.0 s12.5.6.5, HexaPDF::Type::Annotation
47
47
  class Link < Annotation
48
48
 
49
49
  define_field :Subtype, type: Symbol, required: true, default: :Link
@@ -43,7 +43,7 @@ module HexaPDF
43
43
  # Markup annotations are used to "mark up" a PDF document, most of the available PDF
44
44
  # annotations are actually markup annotations.
45
45
  #
46
- # See: PDF1.7 s12.5.6.2, HexaPDF::Type::Annotation
46
+ # See: PDF2.0 s12.5.6.2, HexaPDF::Type::Annotation
47
47
  class MarkupAnnotation < Annotation
48
48
 
49
49
  define_field :T, type: String, version: '1.1'
@@ -43,7 +43,7 @@ module HexaPDF
43
43
  # Text annotations are "sticky notes" attached to a point in a PDF document. They act as if
44
44
  # the NoZoom and NoRotate flags were always set.
45
45
  #
46
- # See: PDF1.7 s12.5.6.4, HexaPDF::Type::MarkupAnnotation
46
+ # See: PDF2.0 s12.5.6.4, HexaPDF::Type::MarkupAnnotation
47
47
  class Text < MarkupAnnotation
48
48
 
49
49
  define_field :Subtype, type: Symbol, required: true, default: :Text
@@ -55,8 +55,7 @@ module HexaPDF
55
55
 
56
56
  private
57
57
 
58
- # :nodoc:
59
- STATE_TO_STATE_MODEL = {
58
+ STATE_TO_STATE_MODEL = { # :nodoc:
60
59
  "Marked" => "Marked", "Unmarked" => "Marked",
61
60
  "Accepted" => "Review", "Rejected" => "Review", "Cancelled" => "Review",
62
61
  "Completed" => "Review", "None" => "Review"
@@ -45,7 +45,7 @@ module HexaPDF
45
45
  # Widget annotations are used by interactive forms to represent the appearance of fields and
46
46
  # to manage user interactions.
47
47
  #
48
- # See: PDF1.7 s12.5.6.19, HexaPDF::Type::Annotation
48
+ # See: PDF2.0 s12.5.6.19, HexaPDF::Type::Annotation
49
49
  class Widget < Annotation
50
50
 
51
51
  # The dictionary used by the /MK key of the widget annotation.
@@ -264,7 +264,7 @@ module HexaPDF
264
264
  # the /DA key on the widget (although /DA is not defined for widget, this is how Acrobat
265
265
  # does it).
266
266
  #
267
- # See: PDF1.7 s12.5.6.19 and s17.7.3.3
267
+ # See: PDF2.0 s12.5.6.19 and s12.7.4.3
268
268
  def marker_style(style: nil, size: nil, color: nil)
269
269
  field = form_field
270
270
  if style || size || color
@@ -41,7 +41,7 @@ module HexaPDF
41
41
 
42
42
  # Namespace module for all PDF annotation dictionary types.
43
43
  #
44
- # See: PDF1.7 s12.5.6, Annotation
44
+ # See: PDF2.0 s12.5.6, Annotation
45
45
  module Annotations
46
46
 
47
47
  autoload(:MarkupAnnotation, 'hexapdf/type/annotations/markup_annotation')
@@ -46,7 +46,7 @@ module HexaPDF
46
46
  #
47
47
  # The catalog dictionary is linked via the /Root entry from the Trailer.
48
48
  #
49
- # See: PDF1.7 s7.7.2, Trailer
49
+ # See: PDF2.0 s7.7.2, Trailer
50
50
  class Catalog < Dictionary
51
51
 
52
52
  define_type :Catalog
@@ -78,7 +78,7 @@ module HexaPDF
78
78
  define_field :SpiderInfo, type: Dictionary, version: '1.3'
79
79
  define_field :OutputIntents, type: PDFArray, version: '1.4'
80
80
  define_field :PieceInfo, type: Dictionary, version: '1.4'
81
- define_field :OCProperties, type: Dictionary, version: '1.5'
81
+ define_field :OCProperties, type: :XXOCProperties, version: '1.5'
82
82
  define_field :Perms, type: Dictionary, version: '1.5'
83
83
  define_field :Legal, type: Dictionary, version: '1.5'
84
84
  define_field :Requirements, type: PDFArray, version: '1.7'
@@ -112,6 +112,15 @@ module HexaPDF
112
112
  self[:Outlines] ||= document.add({}, type: :Outlines)
113
113
  end
114
114
 
115
+ # Returns the optional content properties dictionary, creating it if needed.
116
+ #
117
+ # This is the main entry point for working with optional content, a.k.a. layers.
118
+ #
119
+ # See: OptionalContentProperties
120
+ def optional_content
121
+ self[:OCProperties] ||= document.add({OCGs: [], D: {Creator: 'HexaPDF'}}, type: :XXOCProperties)
122
+ end
123
+
115
124
  # Returns the main AcroForm object.
116
125
  #
117
126
  # * If an AcroForm object exists, the +create+ argument is not used.
@@ -42,13 +42,27 @@ module HexaPDF
42
42
  # Represents a generic CIDFont which can only be used as a descendant font of a composite PDF
43
43
  # font.
44
44
  #
45
- # See: PDF1.7 s9.7.4
45
+ # See: PDF2.0 s9.7.4
46
46
  class CIDFont < Font
47
47
 
48
+ # Describes the CIDSystemInfo dictionary specifying the character collection assumed by the
49
+ # CIDFont.
50
+ #
51
+ # See: PDF2.0 s9.7.3
52
+ class CIDSystemInfo < Dictionary
53
+
54
+ define_type :XXCIDSystemInfo
55
+
56
+ define_field :Registry, type: String, required: true
57
+ define_field :Ordering, type: String, required: true
58
+ define_field :Supplement, type: Integer, required: true
59
+
60
+ end
61
+
48
62
  DEFAULT_WIDTH = 1000 # :nodoc:
49
63
 
50
64
  define_field :BaseFont, type: Symbol, required: true
51
- define_field :CIDSystemInfo, type: Dictionary, required: true
65
+ define_field :CIDSystemInfo, type: :XXCIDSystemInfo, required: true
52
66
  define_field :FontDescriptor, type: :FontDescriptor, indirect: true, required: true
53
67
  define_field :DW, type: Integer, default: DEFAULT_WIDTH
54
68
  define_field :W, type: PDFArray
@@ -66,7 +80,7 @@ module HexaPDF
66
80
  # Sets the /W and /DW keys using the given array of [CID, width] pairs and an optional default
67
81
  # width.
68
82
  #
69
- # See: PDF1.7 s9.7.4.3
83
+ # See: PDF2.0 s9.7.4.3
70
84
  def set_widths(widths, default_width: DEFAULT_WIDTH)
71
85
  if widths.empty?
72
86
  (default_width == DEFAULT_WIDTH ? delete(:DW) : self[:DW] = default_width)
@@ -93,7 +107,7 @@ module HexaPDF
93
107
  #
94
108
  # Note that the hash is cached internally when accessed the first time.
95
109
  #
96
- # See: PDF1.7 s9.7.4.3
110
+ # See: PDF2.0 s9.7.4.3
97
111
  def widths
98
112
  cache(:widths) do
99
113
  result = {}
@@ -46,7 +46,7 @@ module HexaPDF
46
46
  # Type::FileSpecification dictionary or with the document as a whole through the /EmbeddedFiles
47
47
  # entry in the document catalog's /Names dictionary.
48
48
  #
49
- # See: PDF1.7 s7.11.4, FileSpecification
49
+ # See: PDF2.0 s7.11.4, FileSpecification
50
50
  class EmbeddedFile < Stream
51
51
 
52
52
  # The type used for the /Mac field of an EmbeddedFile::Parameters dictionary.