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
@@ -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