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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +104 -1
- data/README.md +9 -0
- data/examples/002-graphics.rb +15 -17
- data/examples/003-arcs.rb +9 -9
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +2 -2
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +7 -7
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +8 -7
- data/examples/016-frame_automatic_box_placement.rb +2 -2
- data/examples/017-frame_text_flow.rb +2 -1
- data/examples/018-composer.rb +1 -1
- data/examples/020-column_box.rb +2 -1
- data/examples/025-table_box.rb +46 -0
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +12 -3
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +5 -7
- data/lib/hexapdf/composer.rb +106 -53
- data/lib/hexapdf/configuration.rb +65 -40
- data/lib/hexapdf/content/canvas.rb +445 -267
- data/lib/hexapdf/content/color_space.rb +72 -25
- data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
- data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
- data/lib/hexapdf/content/graphic_object.rb +6 -7
- data/lib/hexapdf/content/graphics_state.rb +54 -45
- data/lib/hexapdf/content/operator.rb +54 -54
- data/lib/hexapdf/content/parser.rb +2 -2
- data/lib/hexapdf/content/processor.rb +15 -15
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +5 -0
- data/lib/hexapdf/dictionary.rb +7 -5
- data/lib/hexapdf/dictionary_fields.rb +43 -16
- data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
- data/lib/hexapdf/digital_signature/signature.rb +6 -6
- data/lib/hexapdf/digital_signature/signatures.rb +13 -12
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
- data/lib/hexapdf/digital_signature/signing.rb +4 -0
- data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
- data/lib/hexapdf/digital_signature.rb +7 -2
- data/lib/hexapdf/document/destinations.rb +12 -11
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/layout.rb +170 -39
- data/lib/hexapdf/document/pages.rb +4 -3
- data/lib/hexapdf/document.rb +96 -55
- data/lib/hexapdf/encryption/aes.rb +5 -5
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +31 -24
- data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
- data/lib/hexapdf/encryption.rb +7 -2
- data/lib/hexapdf/error.rb +18 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +55 -6
- data/lib/hexapdf/font/cmap/parser.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +3 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
- data/lib/hexapdf/font/type1_wrapper.rb +19 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
- data/lib/hexapdf/font_loader/from_file.rb +5 -5
- data/lib/hexapdf/font_loader/standard14.rb +3 -3
- data/lib/hexapdf/font_loader.rb +3 -0
- data/lib/hexapdf/image_loader/jpeg.rb +2 -2
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +13 -0
- data/lib/hexapdf/layout/box.rb +32 -5
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +20 -5
- data/lib/hexapdf/layout/frame.rb +53 -18
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +21 -9
- data/lib/hexapdf/layout/list_box.rb +50 -20
- data/lib/hexapdf/layout/page_style.rb +6 -5
- data/lib/hexapdf/layout/style.rb +64 -9
- data/lib/hexapdf/layout/table_box.rb +684 -0
- data/lib/hexapdf/layout/text_box.rb +12 -3
- data/lib/hexapdf/layout/text_fragment.rb +29 -3
- data/lib/hexapdf/layout/text_layouter.rb +32 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +18 -7
- data/lib/hexapdf/parser.rb +7 -7
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +3 -3
- data/lib/hexapdf/serializer.rb +15 -15
- data/lib/hexapdf/stream.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +14 -14
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +2 -2
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
- data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +1 -1
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +2 -1
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +2 -3
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +11 -2
- data/lib/hexapdf/type/cid_font.rb +18 -4
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +3 -3
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +76 -6
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +46 -21
- data/lib/hexapdf/type/page_label.rb +5 -9
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +4 -4
- data/lib/hexapdf/xref_section.rb +2 -2
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
- data/test/hexapdf/content/test_canvas.rb +49 -1
- data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
- data/test/hexapdf/document/test_files.rb +2 -2
- data/test/hexapdf/document/test_layout.rb +105 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +12 -11
- data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
- data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
- data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
- data/test/hexapdf/layout/test_box.rb +14 -5
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +27 -15
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +84 -33
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +60 -0
- data/test/hexapdf/layout/test_table_box.rb +728 -0
- data/test/hexapdf/layout/test_text_box.rb +26 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +36 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +5 -0
- data/test/hexapdf/test_filter.rb +8 -0
- data/test/hexapdf/test_importer.rb +9 -0
- data/test/hexapdf/test_object.rb +16 -5
- data/test/hexapdf/test_stream.rb +7 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
- data/test/hexapdf/type/acro_form/test_form.rb +4 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +20 -6
- 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:
|
|
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!(/\\\//, "/") #
|
|
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
|
#
|
|
45
45
|
# A simple font has only single-byte character codes and only supports horizontal metrics.
|
|
46
46
|
#
|
|
47
|
-
# See:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
data/lib/hexapdf/type/form.rb
CHANGED
|
@@ -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:
|
|
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:
|
|
57
|
-
define_field :Ref, type:
|
|
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
|
-
|
|
119
|
-
|
|
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
|
data/lib/hexapdf/type/image.rb
CHANGED
data/lib/hexapdf/type/info.rb
CHANGED
|
@@ -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:
|
|
45
|
+
# See: PDF2.0 s14.7.1
|
|
46
46
|
class MarkInformation < Dictionary
|
|
47
47
|
|
|
48
48
|
define_type :XXMarkInformation
|
data/lib/hexapdf/type/names.rb
CHANGED
|
@@ -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:
|
|
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:
|
|
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
|
|
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
|