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
@@ -60,7 +60,7 @@ module HexaPDF
60
60
  # is useful to provide embedding/unembedding operations in this class, see #embed and
61
61
  # #unembed.
62
62
  #
63
- # See: PDF1.7 s7.11
63
+ # See: PDF2.0 s7.11
64
64
  class FileSpecification < Dictionary
65
65
 
66
66
  # The type used for the /EF field of a FileSpecification
@@ -107,7 +107,7 @@ module HexaPDF
107
107
  # /Unix, /Mac and /DOS).
108
108
  def path
109
109
  tmp = (self[:UF] || self[:F] || self[:Unix] || self[:Mac] || self[:DOS] || '').dup
110
- tmp.gsub!(/\\\//, "/") # PDF1.7 s7.11.2.1 but / in filename is interpreted as separator!
110
+ tmp.gsub!(/\\\//, "/") # PDF2.0 s7.11.2.1 but / in filename is interpreted as separator!
111
111
  tmp.tr!("\\", "/") # always use slashes instead of back-slashes!
112
112
  tmp
113
113
  end
@@ -44,7 +44,7 @@ module HexaPDF
44
44
  # This class specifies metrics and other attributes of a simple font or a CID font as a
45
45
  # whole.
46
46
  #
47
- # See: PDF1.7 s9.8
47
+ # See: PDF2.0 s9.8
48
48
  class FontDescriptor < Dictionary
49
49
 
50
50
  extend Utils::BitField
@@ -44,7 +44,7 @@ module HexaPDF
44
44
  #
45
45
  # A simple font has only single-byte character codes and only supports horizontal metrics.
46
46
  #
47
- # See: PDF1.7 s9.6
47
+ # See: PDF2.0 s9.6
48
48
  class FontSimple < Font
49
49
 
50
50
  define_field :FirstChar, type: Integer
@@ -129,7 +129,7 @@ module HexaPDF
129
129
  #
130
130
  # Always returns +true+ for simple fonts.
131
131
  #
132
- # See: PDF1.7 s9.3.3
132
+ # See: PDF2.0 s9.3.3
133
133
  def word_spacing_applicable?
134
134
  true
135
135
  end
@@ -48,7 +48,7 @@ module HexaPDF
48
48
  # Composite fonts also allow for vertical writing mode and support TrueType as well as OpenType
49
49
  # fonts.
50
50
  #
51
- # See: PDF1.7 s9.7
51
+ # See: PDF2.0 s9.7
52
52
  class FontType0 < Font
53
53
 
54
54
  define_field :Subtype, type: Symbol, required: true, default: :Type0
@@ -110,7 +110,7 @@ module HexaPDF
110
110
  #
111
111
  # Note that the return value is cached when accessed the first time.
112
112
  #
113
- # See: PDF1.7 s9.3.3
113
+ # See: PDF2.0 s9.3.3
114
114
  def word_spacing_applicable?
115
115
  @word_spacing_applicable ||= ((cmap.read_codes("\x20") && true) rescue false)
116
116
  end
@@ -138,7 +138,7 @@ module HexaPDF
138
138
  #
139
139
  # Note that the CMap is cached internally when accessed the first time.
140
140
  #
141
- # See: PDF1.7 s9.10.2
141
+ # See: PDF2.0 s9.10.2
142
142
  def ucs2_cmap
143
143
  cache(:ucs2_cmap) do
144
144
  encoding = self[:Encoding]
@@ -45,7 +45,7 @@ module HexaPDF
45
45
  # If it is of a different form, things won't work correctly. This will be handled once such a
46
46
  # case is found.
47
47
  #
48
- # See: PDF1.7 s9.6.5
48
+ # See: PDF2.0 s9.6.4
49
49
  class FontType3 < FontSimple
50
50
 
51
51
  define_field :Subtype, type: Symbol, required: true, default: :Type3
@@ -34,6 +34,7 @@
34
34
  # commercial licenses are available at <https://gettalong.at/hexapdf/>.
35
35
  #++
36
36
 
37
+ require 'stringio'
37
38
  require 'hexapdf/stream'
38
39
  require 'hexapdf/content'
39
40
 
@@ -42,9 +43,35 @@ module HexaPDF
42
43
 
43
44
  # Represents a form XObject of a PDF document.
44
45
  #
45
- # See: PDF1.7 s8.10
46
+ # See: PDF2.0 s8.10
46
47
  class Form < Stream
47
48
 
49
+ # Represents a group attribute dictionary.
50
+ #
51
+ # See: PDF2.0 s8.10.3
52
+ class Group < Dictionary
53
+
54
+ define_type :Group
55
+
56
+ define_field :Type, type: Symbol, default: type
57
+ define_field :S, type: Symbol, required: true
58
+
59
+ end
60
+
61
+ # Represents a reference dictionary which allows an XObject to refer to content in an embedded
62
+ # or linked PDF document.
63
+ #
64
+ # See: PDF2.0 s8.10.4
65
+ class Reference < Dictionary
66
+
67
+ define_type :XXReference
68
+
69
+ define_field :F, type: :Filespec, required: true
70
+ define_field :Page, type: [Integer, String], required: true
71
+ define_field :ID, type: PDFArray
72
+
73
+ end
74
+
48
75
  define_type :XObject
49
76
 
50
77
  define_field :Type, type: Symbol, default: type
@@ -53,8 +80,8 @@ module HexaPDF
53
80
  define_field :BBox, type: Rectangle, required: true
54
81
  define_field :Matrix, type: PDFArray, default: [1, 0, 0, 1, 0, 0]
55
82
  define_field :Resources, type: :XXResources, version: '1.2'
56
- define_field :Group, type: Dictionary, version: '1.4'
57
- define_field :Ref, type: Dictionary, version: '1.4'
83
+ define_field :Group, type: :Group, version: '1.4'
84
+ define_field :Ref, type: :XXReference, version: '1.4'
58
85
  define_field :Metadata, type: Stream, version: '1.4'
59
86
  define_field :PieceInfo, type: Dictionary, version: '1.3'
60
87
  define_field :LastModified, type: PDFDate, version: '1.3'
@@ -115,14 +142,15 @@ module HexaPDF
115
142
  #
116
143
  # See: HexaPDF::Content::Processor
117
144
  def process_contents(processor, original_resources: nil)
118
- processor.resources = if self[:Resources]
119
- self[:Resources]
145
+ form = referenced_content || self
146
+ processor.resources = if form[:Resources]
147
+ form[:Resources]
120
148
  elsif original_resources
121
149
  original_resources
122
150
  else
123
151
  document.wrap({}, type: :XXResources)
124
152
  end
125
- Content::Parser.parse(contents, processor)
153
+ Content::Parser.parse(form.contents, processor)
126
154
  end
127
155
 
128
156
  # Returns the canvas for the form XObject.
@@ -152,6 +180,48 @@ module HexaPDF
152
180
  end
153
181
  end
154
182
 
183
+ # Returns +true+ if the Form XObject is a reference XObject.
184
+ def reference_xobject?
185
+ !self[:Ref].nil?
186
+ end
187
+
188
+ # Returns the referenced page as Form XObject, if this Form XObject is a Reference XObject and
189
+ # the referenced page is found. Otherwise returns +nil+.
190
+ def referenced_content
191
+ return unless (ref = self[:Ref])
192
+
193
+ doc = if ref[:F].embedded_file?
194
+ HexaPDF::Document.new(io: StringIO.new(ref[:F].embedded_file_stream.stream))
195
+ elsif File.exist?(ref[:F].path)
196
+ HexaPDF::Document.open(ref[:F].path)
197
+ end
198
+ return unless doc
199
+
200
+ page = ref[:Page]
201
+ if page.kind_of?(Integer)
202
+ page = doc.pages[page]
203
+ else
204
+ labels = []
205
+ doc.pages.each_labelling_range do |first_index, count, label|
206
+ count.times {|i| labels << label.construct_label(i) }
207
+ end
208
+ index = labels.index(page)
209
+ page = index && doc.pages[index]
210
+ end
211
+ return unless page
212
+
213
+ # See PDF2.0 s8.10.4.3
214
+ print_annots = page.each_annotation.select {|annot| annot.flagged?(:print) }
215
+ page.flatten_annotations(print_annots) unless print_annots.empty?
216
+
217
+ obj = page.to_form_xobject
218
+ obj[:BBox] = self[:BBox].dup
219
+ obj[:Matrix] = self[:Matrix].dup
220
+ obj
221
+ rescue
222
+ nil
223
+ end
224
+
155
225
  end
156
226
 
157
227
  end
@@ -46,7 +46,7 @@ module HexaPDF
46
46
  # Some parameters can only be set by an operator, some only by the dictionary but most by
47
47
  # both.
48
48
  #
49
- # See: PDF1.7 s8.4.5, s8.1
49
+ # See: PDF2.0 s8.4.5, s8.1
50
50
  class GraphicsStateParameter < Dictionary
51
51
 
52
52
  define_type :ExtGState
@@ -42,7 +42,7 @@ module HexaPDF
42
42
  # An IconFit dictionary specifies how an icon should be displayed inside an annotation
43
43
  # rectangle.
44
44
  #
45
- # See: PDF1.7 s12.7.7.3.2
45
+ # See: PDF2.0 s12.7.8.3.2
46
46
  class IconFit < Annotation
47
47
 
48
48
  define_type :XXIconFit
@@ -45,7 +45,7 @@ module HexaPDF
45
45
 
46
46
  # Represents an image XObject of a PDF document.
47
47
  #
48
- # See: PDF1.7 s8.8
48
+ # See: PDF2.0 s8.8
49
49
  class Image < Stream
50
50
 
51
51
  # The structure that is returned by the Image#info method.
@@ -44,7 +44,7 @@ module HexaPDF
44
44
  # The info dictionary is linked via the /Info entry from the Trailer and contains metadata for
45
45
  # the document.
46
46
  #
47
- # See: PDF1.7 s14.3.3, Trailer
47
+ # See: PDF2.0 s14.3.3, Trailer
48
48
  class Info < Dictionary
49
49
 
50
50
  define_type :XXInfo
@@ -42,7 +42,7 @@ module HexaPDF
42
42
  # Represents the mark information dictionary which provides some general information related to
43
43
  # structured PDF documents.
44
44
  #
45
- # See: PDF1.7 s14.7.1
45
+ # See: PDF2.0 s14.7.1
46
46
  class MarkInformation < Dictionary
47
47
 
48
48
  define_type :XXMarkInformation
@@ -47,7 +47,7 @@ module HexaPDF
47
47
  #
48
48
  # This dictionary is linked via the /Names entry from the HexaPDF::Catalog.
49
49
  #
50
- # See: PDF1.7 s7.7.4, HexaPDF::Catalog, HexaPDF::NameTreeNode
50
+ # See: PDF2.0 s7.7.4, HexaPDF::Catalog, HexaPDF::NameTreeNode
51
51
  class Names < Dictionary
52
52
 
53
53
  define_type :XXNames
@@ -71,7 +71,7 @@ module HexaPDF
71
71
  # provides a much easier to work with convenience interface for working with destination
72
72
  # objects.
73
73
  #
74
- # See: PDF1.7 s12.3.2
74
+ # See: PDF2.0 s12.3.2
75
75
  def destinations
76
76
  self[:Dests] ||= document.add({}, type: NameTreeNode)
77
77
  end
@@ -70,7 +70,7 @@ module HexaPDF
70
70
  # However, only objects that can be written to the object stream are actually written. The
71
71
  # other objects are deleted from the object stream (#delete_object) and written normally.
72
72
  #
73
- # See PDF1.7 s7.5.7
73
+ # See PDF2.0 s7.5.7
74
74
  class ObjectStream < HexaPDF::Stream
75
75
 
76
76
  # Holds all necessary information to load objects for an object stream.
@@ -114,6 +114,7 @@ module HexaPDF
114
114
  return @stream_data if defined?(@stream_data)
115
115
  data = stream
116
116
  oids, offsets = parse_oids_and_offsets(data)
117
+ @objects ||= {}
117
118
  oids.each {|oid| add_object(Reference.new(oid, 0)) }
118
119
  @stream_data = Data.new(data, oids, offsets)
119
120
  end
@@ -0,0 +1,170 @@
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/dictionary'
38
+
39
+ module HexaPDF
40
+ module Type
41
+
42
+ # Represents an optional content configuration dictionary.
43
+ #
44
+ # This dictionary is used for the /D and /Configs entries in the optional content properties
45
+ # dictionary. It configures the states of the OCGs as well as defines how those states may be
46
+ # changed by a PDF processor.
47
+ #
48
+ # See: PDF2.0 s8.11.4.3
49
+ class OptionalContentConfiguration < Dictionary
50
+
51
+ # Represents an optional content usage application dictionary.
52
+ #
53
+ # This dictionary is used for the elements in the /AS array of an optional content
54
+ # configuration dictionary. It specifies how a PDF processor should use the usage entries of
55
+ # OCGs to automatically change their state based on external factors (like magnifacation
56
+ # factor or language).
57
+ #
58
+ # See: PDF2.0 s8.11.4.4
59
+ class UsageApplication < Dictionary
60
+ define_type :XXOCUsageApplication
61
+ define_field :Event, type: Symbol, required: true, allowed_values: [:View, :Print, :Export]
62
+ define_field :OCGs, type: PDFArray, default: []
63
+ define_field :Category, type: PDFArray, required: true
64
+ end
65
+
66
+ define_type :XXOCConfiguration
67
+
68
+ define_field :Name, type: String
69
+ define_field :Creator, type: String
70
+ define_field :BaseState, type: Symbol, default: :ON, allowed_values: [:ON, :OFF, :Unchanged]
71
+ define_field :ON, type: PDFArray
72
+ define_field :OFF, type: PDFArray
73
+ define_field :Intent, type: [Symbol, PDFArray], default: :View
74
+ define_field :AS, type: PDFArray
75
+ define_field :Order, type: PDFArray
76
+ define_field :ListMode, type: Symbol, default: :AllPages,
77
+ allowed_values: [:AllPages, :VisiblePages]
78
+ define_field :RBGroups, type: PDFArray
79
+ define_field :Locked, type: PDFArray, default: []
80
+
81
+ # :call-seq:
82
+ # configuration.ocg_state(ocg) -> state
83
+ # configuration.ocg_state(ocg, state) -> state
84
+ #
85
+ # Returns the state (+:on+, +:off+ or +nil+) of the optional content group if the +state+
86
+ # argument is not given. Otherwise sets the state of the OCG to the given state value
87
+ # (+:on+/+:ON+ or +:off+/+:OFF+).
88
+ #
89
+ # The value +nil+ is only returned if the state is not defined by the configuration dictionary
90
+ # (which may only be the case if the configuration dictionary is not the default configuration
91
+ # dictionary).
92
+ def ocg_state(ocg, state = nil)
93
+ if state.nil?
94
+ case self[:BaseState]
95
+ when :ON then self[:OFF]&.include?(ocg) ? :off : :on
96
+ when :OFF then self[:ON]&.include?(ocg) ? :on : :off
97
+ else self[:OFF]&.include?(ocg) ? :off : (self[:ON]&.include?(ocg) ? :on : nil)
98
+ end
99
+ elsif state&.downcase == :on
100
+ (self[:ON] ||= []) << ocg unless self[:ON]&.include?(ocg)
101
+ self[:OFF].delete(ocg) if key?(:OFF)
102
+ elsif state&.downcase == :off
103
+ (self[:OFF] ||= []) << ocg unless self[:OFF]&.include?(ocg)
104
+ self[:ON].delete(ocg) if key?(:ON)
105
+ else
106
+ raise ArgumentError, "Invalid value #{state.inspect} for state argument"
107
+ end
108
+ end
109
+
110
+ # Returns +true+ if the given optional content group is on.
111
+ def ocg_on?(ocg)
112
+ ocg_state(ocg) == :on
113
+ end
114
+
115
+ # Makes the given optional content group visible in an interactive PDF processor's user
116
+ # interface.
117
+ #
118
+ # The OCG is always added to the end of the specified +path+ or, if +path+ is not specified,
119
+ # the top level.
120
+ #
121
+ # The optional argument +path+ specifies the strings or OCGs under which the given OCG should
122
+ # hierarchically be nested. A string is used as a non-selectable label, an OCG reflects an
123
+ # actual nesting of the involved OCGs.
124
+ #
125
+ # Examples:
126
+ #
127
+ # configuration.add_ocg_to_ui(ocg) # Add the OCG as top-level item
128
+ # configuration.add_ocg_to_ui(ocg, path: 'Debug') # Add the OCG under the label 'Debug'
129
+ # # Add the OCG under the label 'Page1' which is under the label 'Debug'
130
+ # configuration.add_ocg_to_ui(ocg, path: ['Debug', 'Page1'])
131
+ # configuration.add_ocg_to_ui(ocg, path: other_ocg) # Add the OCG under the other OCG
132
+ def add_ocg_to_ui(ocg, path: nil)
133
+ array = self[:Order] ||= []
134
+ path = Array(path)
135
+ until path.empty?
136
+ item = path.shift
137
+ index = array.index do |entry|
138
+ if (entry.kind_of?(Array) || entry.kind_of?(PDFArray)) && item.kind_of?(String)
139
+ entry.first == item
140
+ else
141
+ entry == item
142
+ end
143
+ end
144
+
145
+ if item.kind_of?(String)
146
+ unless index
147
+ array << [item]
148
+ index = -1
149
+ end
150
+ array = array[index]
151
+ else
152
+ unless index
153
+ array << item << []
154
+ index = -2
155
+ end
156
+ if array[index + 1].kind_of?(Array) || array[index + 1].kind_of?(PDFArray)
157
+ array = array[index + 1]
158
+ else
159
+ array.insert(index + 1, [])
160
+ array = array[index + 1]
161
+ end
162
+ end
163
+ end
164
+ array << ocg
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+ end