hexapdf 0.11.7 → 0.12.2

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 (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +121 -0
  3. data/LICENSE +1 -1
  4. data/examples/001-hello_world.rb +1 -1
  5. data/examples/002-graphics.rb +1 -1
  6. data/examples/003-arcs.rb +1 -1
  7. data/examples/004-optimizing.rb +1 -1
  8. data/examples/005-merging.rb +1 -1
  9. data/examples/006-standard_pdf_fonts.rb +1 -1
  10. data/examples/007-truetype.rb +1 -1
  11. data/examples/008-show_char_bboxes.rb +1 -1
  12. data/examples/009-text_layouter_alignment.rb +1 -1
  13. data/examples/010-text_layouter_inline_boxes.rb +1 -1
  14. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  15. data/examples/012-text_layouter_styling.rb +1 -1
  16. data/examples/013-text_layouter_shapes.rb +1 -1
  17. data/examples/014-text_in_polygon.rb +1 -1
  18. data/examples/015-boxes.rb +1 -1
  19. data/examples/016-frame_automatic_box_placement.rb +1 -1
  20. data/examples/017-frame_text_flow.rb +1 -1
  21. data/examples/018-composer.rb +1 -1
  22. data/examples/019-acro_form.rb +51 -0
  23. data/lib/hexapdf.rb +1 -1
  24. data/lib/hexapdf/cli.rb +3 -1
  25. data/lib/hexapdf/cli/batch.rb +1 -1
  26. data/lib/hexapdf/cli/command.rb +18 -9
  27. data/lib/hexapdf/cli/files.rb +1 -1
  28. data/lib/hexapdf/cli/form.rb +240 -0
  29. data/lib/hexapdf/cli/image2pdf.rb +1 -1
  30. data/lib/hexapdf/cli/images.rb +1 -1
  31. data/lib/hexapdf/cli/info.rb +1 -1
  32. data/lib/hexapdf/cli/inspect.rb +1 -1
  33. data/lib/hexapdf/cli/merge.rb +1 -1
  34. data/lib/hexapdf/cli/modify.rb +1 -1
  35. data/lib/hexapdf/cli/optimize.rb +1 -1
  36. data/lib/hexapdf/cli/split.rb +1 -1
  37. data/lib/hexapdf/cli/watermark.rb +1 -1
  38. data/lib/hexapdf/composer.rb +2 -2
  39. data/lib/hexapdf/configuration.rb +66 -11
  40. data/lib/hexapdf/content.rb +3 -1
  41. data/lib/hexapdf/content/canvas.rb +5 -18
  42. data/lib/hexapdf/content/color_space.rb +111 -32
  43. data/lib/hexapdf/content/graphic_object.rb +1 -1
  44. data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
  45. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  46. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  47. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  48. data/lib/hexapdf/content/graphics_state.rb +1 -1
  49. data/lib/hexapdf/content/operator.rb +9 -9
  50. data/lib/hexapdf/content/parser.rb +18 -5
  51. data/lib/hexapdf/content/processor.rb +1 -1
  52. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  53. data/lib/hexapdf/data_dir.rb +1 -1
  54. data/lib/hexapdf/dictionary.rb +1 -1
  55. data/lib/hexapdf/dictionary_fields.rb +1 -1
  56. data/lib/hexapdf/document.rb +14 -5
  57. data/lib/hexapdf/document/files.rb +1 -1
  58. data/lib/hexapdf/document/fonts.rb +1 -1
  59. data/lib/hexapdf/document/images.rb +1 -1
  60. data/lib/hexapdf/document/pages.rb +3 -14
  61. data/lib/hexapdf/encryption.rb +1 -1
  62. data/lib/hexapdf/encryption/aes.rb +1 -1
  63. data/lib/hexapdf/encryption/arc4.rb +1 -1
  64. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  65. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  66. data/lib/hexapdf/encryption/identity.rb +1 -1
  67. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  68. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  69. data/lib/hexapdf/encryption/security_handler.rb +7 -1
  70. data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
  71. data/lib/hexapdf/error.rb +1 -1
  72. data/lib/hexapdf/filter.rb +3 -3
  73. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  74. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  75. data/lib/hexapdf/filter/encryption.rb +1 -1
  76. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  77. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  78. data/lib/hexapdf/filter/{jpx_decode.rb → pass_through.rb} +5 -5
  79. data/lib/hexapdf/filter/predictor.rb +1 -1
  80. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  81. data/lib/hexapdf/font/cmap.rb +1 -1
  82. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  83. data/lib/hexapdf/font/cmap/writer.rb +1 -1
  84. data/lib/hexapdf/font/encoding.rb +1 -1
  85. data/lib/hexapdf/font/encoding/base.rb +9 -1
  86. data/lib/hexapdf/font/encoding/difference_encoding.rb +7 -1
  87. data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
  88. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  89. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  90. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  91. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  92. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
  93. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  94. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  95. data/lib/hexapdf/font/true_type.rb +1 -1
  96. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  97. data/lib/hexapdf/font/true_type/font.rb +1 -1
  98. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  99. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  100. data/lib/hexapdf/font/true_type/table.rb +1 -1
  101. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  102. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  103. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  104. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  105. data/lib/hexapdf/font/true_type/table/head.rb +1 -1
  106. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  107. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  108. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  109. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  110. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  111. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  112. data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
  113. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  114. data/lib/hexapdf/font/true_type_wrapper.rb +54 -51
  115. data/lib/hexapdf/font/type1.rb +1 -1
  116. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  117. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  118. data/lib/hexapdf/font/type1/font.rb +1 -1
  119. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  120. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  121. data/lib/hexapdf/font/type1_wrapper.rb +68 -52
  122. data/lib/hexapdf/font_loader.rb +1 -1
  123. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  124. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  125. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  126. data/lib/hexapdf/image_loader.rb +1 -1
  127. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  128. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  129. data/lib/hexapdf/image_loader/png.rb +1 -1
  130. data/lib/hexapdf/importer.rb +2 -4
  131. data/lib/hexapdf/layout.rb +1 -1
  132. data/lib/hexapdf/layout/box.rb +1 -1
  133. data/lib/hexapdf/layout/frame.rb +1 -1
  134. data/lib/hexapdf/layout/image_box.rb +1 -1
  135. data/lib/hexapdf/layout/inline_box.rb +1 -1
  136. data/lib/hexapdf/layout/line.rb +1 -1
  137. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  138. data/lib/hexapdf/layout/style.rb +1 -1
  139. data/lib/hexapdf/layout/text_box.rb +1 -1
  140. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  141. data/lib/hexapdf/layout/text_layouter.rb +1 -1
  142. data/lib/hexapdf/layout/text_shaper.rb +1 -1
  143. data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
  144. data/lib/hexapdf/name_tree_node.rb +1 -1
  145. data/lib/hexapdf/number_tree_node.rb +1 -1
  146. data/lib/hexapdf/object.rb +2 -2
  147. data/lib/hexapdf/parser.rb +4 -3
  148. data/lib/hexapdf/pdf_array.rb +1 -1
  149. data/lib/hexapdf/rectangle.rb +31 -1
  150. data/lib/hexapdf/reference.rb +1 -1
  151. data/lib/hexapdf/revision.rb +2 -1
  152. data/lib/hexapdf/revisions.rb +1 -1
  153. data/lib/hexapdf/serializer.rb +2 -2
  154. data/lib/hexapdf/stream.rb +1 -1
  155. data/lib/hexapdf/task.rb +1 -1
  156. data/lib/hexapdf/task/dereference.rb +1 -1
  157. data/lib/hexapdf/task/optimize.rb +1 -1
  158. data/lib/hexapdf/tokenizer.rb +1 -1
  159. data/lib/hexapdf/type.rb +1 -1
  160. data/lib/hexapdf/type/acro_form.rb +7 -1
  161. data/lib/hexapdf/type/acro_form/appearance_generator.rb +401 -0
  162. data/lib/hexapdf/type/acro_form/button_field.rb +300 -0
  163. data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
  164. data/lib/hexapdf/type/acro_form/field.rb +220 -17
  165. data/lib/hexapdf/type/acro_form/form.rb +157 -7
  166. data/lib/hexapdf/type/acro_form/text_field.rb +186 -0
  167. data/lib/hexapdf/type/acro_form/variable_text_field.rb +122 -0
  168. data/lib/hexapdf/type/action.rb +1 -1
  169. data/lib/hexapdf/type/actions.rb +1 -1
  170. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  171. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  172. data/lib/hexapdf/type/actions/launch.rb +1 -1
  173. data/lib/hexapdf/type/actions/uri.rb +1 -1
  174. data/lib/hexapdf/type/annotation.rb +73 -3
  175. data/lib/hexapdf/type/annotations.rb +1 -1
  176. data/lib/hexapdf/type/annotations/link.rb +2 -2
  177. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  178. data/lib/hexapdf/type/annotations/text.rb +1 -1
  179. data/lib/hexapdf/type/annotations/widget.rb +239 -2
  180. data/lib/hexapdf/type/catalog.rb +21 -1
  181. data/lib/hexapdf/type/cid_font.rb +1 -1
  182. data/lib/hexapdf/type/embedded_file.rb +1 -1
  183. data/lib/hexapdf/type/file_specification.rb +1 -1
  184. data/lib/hexapdf/type/font.rb +18 -1
  185. data/lib/hexapdf/type/font_descriptor.rb +2 -2
  186. data/lib/hexapdf/type/font_simple.rb +1 -1
  187. data/lib/hexapdf/type/font_true_type.rb +1 -1
  188. data/lib/hexapdf/type/font_type0.rb +1 -1
  189. data/lib/hexapdf/type/font_type1.rb +16 -1
  190. data/lib/hexapdf/type/font_type3.rb +1 -1
  191. data/lib/hexapdf/type/form.rb +10 -1
  192. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  193. data/lib/hexapdf/type/icon_fit.rb +1 -1
  194. data/lib/hexapdf/type/image.rb +3 -1
  195. data/lib/hexapdf/type/info.rb +1 -1
  196. data/lib/hexapdf/type/names.rb +1 -1
  197. data/lib/hexapdf/type/object_stream.rb +1 -1
  198. data/lib/hexapdf/type/page.rb +20 -5
  199. data/lib/hexapdf/type/page_tree_node.rb +8 -11
  200. data/lib/hexapdf/type/resources.rb +16 -3
  201. data/lib/hexapdf/type/trailer.rb +2 -3
  202. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  203. data/lib/hexapdf/type/xref_stream.rb +1 -1
  204. data/lib/hexapdf/utils/bit_field.rb +38 -24
  205. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  206. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  207. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  208. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  209. data/lib/hexapdf/utils/object_hash.rb +1 -1
  210. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  211. data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
  212. data/lib/hexapdf/version.rb +2 -2
  213. data/lib/hexapdf/writer.rb +1 -1
  214. data/lib/hexapdf/xref_section.rb +1 -1
  215. data/test/hexapdf/content/common.rb +2 -2
  216. data/test/hexapdf/content/test_color_space.rb +71 -8
  217. data/test/hexapdf/content/test_operator.rb +22 -22
  218. data/test/hexapdf/content/test_parser.rb +14 -0
  219. data/test/hexapdf/document/test_fonts.rb +1 -1
  220. data/test/hexapdf/document/test_pages.rb +6 -6
  221. data/test/hexapdf/encryption/test_security_handler.rb +4 -0
  222. data/test/hexapdf/font/encoding/test_base.rb +10 -0
  223. data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
  224. data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
  225. data/test/hexapdf/font/test_type1_wrapper.rb +33 -8
  226. data/test/hexapdf/layout/test_style.rb +1 -1
  227. data/test/hexapdf/test_document.rb +12 -0
  228. data/test/hexapdf/test_parser.rb +10 -0
  229. data/test/hexapdf/test_rectangle.rb +14 -0
  230. data/test/hexapdf/test_revision.rb +3 -0
  231. data/test/hexapdf/test_serializer.rb +3 -3
  232. data/test/hexapdf/test_writer.rb +2 -2
  233. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +515 -0
  234. data/test/hexapdf/type/acro_form/test_button_field.rb +276 -0
  235. data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
  236. data/test/hexapdf/type/acro_form/test_field.rb +124 -6
  237. data/test/hexapdf/type/acro_form/test_form.rb +189 -22
  238. data/test/hexapdf/type/acro_form/test_text_field.rb +119 -0
  239. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
  240. data/test/hexapdf/type/annotations/test_text.rb +1 -1
  241. data/test/hexapdf/type/annotations/test_widget.rb +199 -0
  242. data/test/hexapdf/type/test_annotation.rb +45 -0
  243. data/test/hexapdf/type/test_catalog.rb +18 -0
  244. data/test/hexapdf/type/test_font.rb +5 -0
  245. data/test/hexapdf/type/test_font_type1.rb +8 -0
  246. data/test/hexapdf/type/test_form.rb +18 -0
  247. data/test/hexapdf/type/test_image.rb +7 -0
  248. data/test/hexapdf/type/test_page.rb +37 -6
  249. data/test/hexapdf/type/test_page_tree_node.rb +20 -12
  250. data/test/hexapdf/type/test_resources.rb +20 -0
  251. data/test/hexapdf/type/test_trailer.rb +4 -0
  252. data/test/hexapdf/utils/test_bit_field.rb +13 -1
  253. data/test/test_helper.rb +1 -1
  254. metadata +38 -18
  255. data/lib/hexapdf/filter/dct_decode.rb +0 -60
@@ -0,0 +1,186 @@
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-2020 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/error'
38
+ require 'hexapdf/type/acro_form/variable_text_field'
39
+
40
+ module HexaPDF
41
+ module Type
42
+ module AcroForm
43
+
44
+ # AcroForm text fields provide a box or space to fill-in data entered from keyboard. The text
45
+ # may be restricted to a single line or can span multiple lines.
46
+ #
47
+ # == Type Specific Field Flags
48
+ #
49
+ # :multiline:: If set, the text field may contain multiple lines.
50
+ #
51
+ # :password:: The field is a password field. This changes the behaviour of the PDF reader
52
+ # application to not echo the input text and to not store it in the PDF file.
53
+ #
54
+ # :file_select:: The text field represents a file selection control where the input text is
55
+ # the path to a file.
56
+ #
57
+ # :do_not_spell_check:: The text should not be spell-checked.
58
+ #
59
+ # :do_not_scroll:: The text field should not scroll (horizontally for single-line fields and
60
+ # vertically for multiline fields) to accomodate more text than fits into the
61
+ # annotation rectangle. This means that no more text can be entered once the
62
+ # field is full.
63
+ #
64
+ # :comb:: The field is divided into /MaxLen equally spaced positions (so /MaxLen needs to be
65
+ # set). This is useful, for example, when entering things like social security
66
+ # numbers which always have the same length.
67
+ #
68
+ # :rich_text:: The field is a rich text field.
69
+ #
70
+ # See: PDF1.7 s12.7.4.3
71
+ class TextField < VariableTextField
72
+
73
+ define_field :MaxLen, type: Integer
74
+
75
+ # All inheritable dictionary fields for text fields.
76
+ INHERITABLE_FIELDS = (superclass::INHERITABLE_FIELDS + [:MaxLen]).freeze
77
+
78
+ # Updated list of field flags.
79
+ FLAGS_BIT_MAPPING = superclass::FLAGS_BIT_MAPPING.merge(
80
+ {
81
+ multiline: 12,
82
+ password: 13,
83
+ file_select: 20,
84
+ do_not_spell_check: 22,
85
+ do_not_scroll: 23,
86
+ comb: 24,
87
+ rich_text: 25,
88
+ }
89
+ ).freeze
90
+
91
+ # Returns the field value, i.e. the text contents of the field, or +nil+ if no value is set.
92
+ #
93
+ # Note that modifying the returned value *might not* modify the text contents in case it is
94
+ # stored as stream! So always use #field_value= to set the field value.
95
+ def field_value
96
+ return unless value[:V]
97
+ self[:V].kind_of?(String) ? self[:V] : self[:V].stream
98
+ end
99
+
100
+ # Sets the field value, i.e. the text contents of the field, to the given string.
101
+ #
102
+ # Note that for single line text fields, all whitespace characters are changed to simple
103
+ # spaces.
104
+ def field_value=(str)
105
+ if flagged?(:password)
106
+ raise HexaPDF::Error, "Storing a field value for a password field is not allowed"
107
+ end
108
+ str = str.gsub(/[[:space:]]/, ' ') if concrete_field_type == :single_line_text_field
109
+ self[:V] = str
110
+ update_widgets
111
+ end
112
+
113
+ # Returns the default field value.
114
+ #
115
+ # See: #field_value
116
+ def default_field_value
117
+ self[:DV].kind_of?(String) ? self[:DV] : self[:DV].stream
118
+ end
119
+
120
+ # Sets the default field value.
121
+ #
122
+ # See: #field_value=
123
+ def default_field_value=(str)
124
+ self[:DV] = str
125
+ end
126
+
127
+ # Returns the concrete text field type, either :single_line_text_field,
128
+ # :multiline_text_field, :password_field, :file_select_field, :comb_text_field or
129
+ # :rich_text_field.
130
+ def concrete_field_type
131
+ if flagged?(:multiline)
132
+ :multiline_text_field
133
+ elsif flagged?(:password)
134
+ :password_field
135
+ elsif flagged?(:file_select)
136
+ :file_select_field
137
+ elsif flagged?(:comb)
138
+ :comb_text_field
139
+ elsif flagged?(:rich_text)
140
+ :rich_text_field
141
+ else
142
+ :single_line_text_field
143
+ end
144
+ end
145
+
146
+ # Creates appropriate appearances for all widgets.
147
+ #
148
+ # For information on how this is done see AppearanceGenerator.
149
+ #
150
+ # Note that an appearance for a text field widget is *always* created even if there is an
151
+ # existing one to make sure the current field value is properly represented.
152
+ def create_appearances
153
+ appearance_generator_class = document.config.constantize('acro_form.appearance_generator')
154
+ each_widget do |widget|
155
+ appearance_generator_class.new(widget).create_text_appearances
156
+ end
157
+ end
158
+
159
+ # Updates the widgets so that they reflect the current field value.
160
+ def update_widgets
161
+ create_appearances
162
+ end
163
+
164
+ private
165
+
166
+ def perform_validation #:nodoc:
167
+ if field_type != :Tx
168
+ yield("Field /FT of AcroForm text field has to be :Tx", true)
169
+ self[:FT] = :Tx
170
+ end
171
+
172
+ super
173
+
174
+ if self[:V] && !(self[:V].kind_of?(String) || self[:V].kind_of?(HexaPDF::Stream))
175
+ yield("Text field doesn't contain text but #{self[:V].class} object")
176
+ end
177
+ if (max_len = self[:MaxLen]) && field_value.length > max_len
178
+ yield("Text contents of field '#{full_field_name}' is too long")
179
+ end
180
+ end
181
+
182
+ end
183
+
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,122 @@
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-2020 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/dictionary'
38
+ require 'hexapdf/stream'
39
+ require 'hexapdf/error'
40
+ require 'hexapdf/content/parser'
41
+
42
+ module HexaPDF
43
+ module Type
44
+ module AcroForm
45
+
46
+ # An AcroForm variable text field defines how text that it is not known at generation time
47
+ # should be rendered. For example, AcroForm text fields (normally) don't have an initial
48
+ # value; the value is entered by the user and needs to be rendered correctly by the PDF
49
+ # reader.
50
+ #
51
+ # See: PDF1.7 s12.7.3.3
52
+ class VariableTextField < Field
53
+
54
+ define_field :DA, type: String
55
+ define_field :Q, type: Integer, default: 0, allowed_values: [0, 1, 2]
56
+ define_field :DS, type: String, version: '1.5'
57
+ define_field :RV, type: [String, Stream], version: '1.5'
58
+
59
+ # All inheritable dictionary fields for text fields.
60
+ INHERITABLE_FIELDS = (superclass::INHERITABLE_FIELDS + [:DA, :Q]).freeze
61
+
62
+ UNSET_ARG = ::Object.new # :nodoc:
63
+
64
+ # :call-seq:
65
+ # field.text_alignment -> alignment
66
+ # field.text_alignment(alignment) -> field
67
+ #
68
+ # Sets or returns the text alignment that should be used when displaying text.
69
+ #
70
+ # With no argument, the current text alignment is returned. When a value is provided, the
71
+ # text alignment is set accordingly.
72
+ #
73
+ # The alignment value is one of :left, :center or :right.
74
+ def text_alignment(alignment = UNSET_ARG)
75
+ if alignment == UNSET_ARG
76
+ case self[:Q]
77
+ when 0 then :left
78
+ when 1 then :center
79
+ when 2 then :right
80
+ end
81
+ else
82
+ self[:Q] = case alignment
83
+ when :left then 0
84
+ when :center then 1
85
+ when :right then 2
86
+ else
87
+ raise ArgumentError, "Invalid variable text field alignment #{alignment}"
88
+ end
89
+ end
90
+ end
91
+
92
+ # Sets the default appearance string using the provided values.
93
+ #
94
+ # The default argument values are a sane default. If +font_size+ is set to 0, the font size
95
+ # is calculated using the height/width of the field.
96
+ def set_default_appearance_string(font: 'Helvetica', font_size: 0)
97
+ name = document.acro_form(create: true).default_resources.
98
+ add_font(document.fonts.add(font).pdf_object)
99
+ self[:DA] = "0 g /#{name} #{font_size} Tf"
100
+ end
101
+
102
+ # Parses the default appearance string and returns an array containing [font_name,
103
+ # font_size].
104
+ #
105
+ # The default appearance string is taken from the field or, if not set, the default
106
+ # appearance string of the form.
107
+ def parse_default_appearance_string
108
+ da = self[:DA] || (document.acro_form && document.acro_form[:DA])
109
+ raise HexaPDF::Error, "No default appearance string set" unless da
110
+
111
+ font_params = nil
112
+ HexaPDF::Content::Parser.parse(da) do |obj, params|
113
+ font_params = params.dup if obj == :Tf
114
+ end
115
+ font_params
116
+ end
117
+
118
+ end
119
+
120
+ end
121
+ end
122
+ end
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -46,6 +46,54 @@ module HexaPDF
46
46
  # See: PDF1.7 s12.5
47
47
  class Annotation < Dictionary
48
48
 
49
+ # The appearance dictionary references appearance streams for various use cases.
50
+ #
51
+ # Each appearance can either be an XObject or a dictionary mapping names to XObjects. The
52
+ # latter is used when the appearance depends on the state of the annotation, e.g. a check box
53
+ # widget that can be checked or unchecked.
54
+ #
55
+ # See: PDF1.7 s12.5.5
56
+ class AppearanceDictionary < Dictionary
57
+
58
+ define_type :XXAppearanceDictionary
59
+
60
+ define_field :N, type: [Dictionary, Stream], required: true
61
+ define_field :R, type: [Dictionary, Stream]
62
+ define_field :D, type: [Dictionary, Stream]
63
+
64
+ # The annotation's normal appearance.
65
+ def normal_appearance
66
+ self[:N]
67
+ end
68
+
69
+ # The rollover appearance which should be used when the cursor is moved into the active area
70
+ # of the annotation without pressing a button.
71
+ def rollover_appearance
72
+ self[:R] || self[:N]
73
+ end
74
+
75
+ # The down appearance which should be used when the mouse button is pressed or held down
76
+ # inside the active area of the annotation.
77
+ def down_appearance
78
+ self[:D] || self[:N]
79
+ end
80
+
81
+ end
82
+
83
+ # Border style dictionary used by various annotation types.
84
+ #
85
+ # See: PDF1.7 s12.5.4
86
+ class Border < Dictionary
87
+
88
+ define_type :Border
89
+
90
+ define_field :Type, type: Symbol, default: type
91
+ define_field :W, type: [Integer, Float], default: 1
92
+ define_field :S, type: Symbol, default: :S, allowed_values: [:S, :D, :B, :I, :U]
93
+ define_field :D, type: PDFArray, default: [3]
94
+
95
+ end
96
+
49
97
  extend Utils::BitField
50
98
 
51
99
  define_type :Annot
@@ -58,7 +106,7 @@ module HexaPDF
58
106
  define_field :NM, type: String, version: '1.4'
59
107
  define_field :M, type: PDFDate, version: '1.1'
60
108
  define_field :F, type: Integer, default: 0, version: '1.1'
61
- define_field :AP, type: Dictionary, version: '1.2'
109
+ define_field :AP, type: :XXAppearanceDictionary, version: '1.2'
62
110
  define_field :AS, type: Symbol, version: '1.2'
63
111
  define_field :Border, type: PDFArray, default: [0, 0, 1]
64
112
  define_field :C, type: PDFArray, version: '1.1'
@@ -68,7 +116,29 @@ module HexaPDF
68
116
  bit_field(:raw_flags, {invisible: 0, hidden: 1, print: 2, no_zoom: 3, no_rotate: 4,
69
117
  no_view: 5, read_only: 6, locked: 7, toggle_no_view: 8,
70
118
  locked_contents: 9},
71
- lister: "flags", getter: "flagged?", setter: "flag")
119
+ lister: "flags", getter: "flagged?", setter: "flag", unsetter: "unflag")
120
+
121
+ # Returns +true+ because annotation objects must always be indirect objects.
122
+ def must_be_indirect?
123
+ true
124
+ end
125
+
126
+ # Returns the AppearanceDictionary instance associated with the annotation or +nil+ if none is
127
+ # set.
128
+ def appearance
129
+ self[:AP]
130
+ end
131
+
132
+ # Returns +true+ if the widget's normal appearance exists.
133
+ #
134
+ # Note that this checks only if the appearance exists but not if the structure of the
135
+ # appearance dictionary conforms to the expectations of the annotation.
136
+ def appearance?
137
+ return false unless (normal_appearance = appearance&.normal_appearance)
138
+ normal_appearance.kind_of?(HexaPDF::Stream) ||
139
+ (!normal_appearance.empty? &&
140
+ normal_appearance.each.all? {|_k, v| v.kind_of?(HexaPDF::Stream) })
141
+ end
72
142
 
73
143
  private
74
144