hexapdf 0.32.2 → 0.34.0

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