hexapdf 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTERS +1 -1
- data/Rakefile +35 -50
- data/VERSION +1 -1
- data/lib/hexapdf/cli.rb +4 -0
- data/lib/hexapdf/cli/command.rb +6 -2
- data/lib/hexapdf/cli/image2pdf.rb +141 -0
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +32 -2
- data/lib/hexapdf/cli/modify.rb +1 -1
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +130 -0
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +7 -1
- data/lib/hexapdf/content/canvas.rb +2 -2
- data/lib/hexapdf/content/graphic_object/arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/dictionary.rb +11 -3
- data/lib/hexapdf/dictionary_fields.rb +32 -3
- data/lib/hexapdf/document.rb +7 -3
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +21 -1
- data/lib/hexapdf/document/pages.rb +2 -2
- data/lib/hexapdf/encryption/standard_security_handler.rb +2 -2
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +2 -2
- data/lib/hexapdf/font/true_type/table/os2.rb +4 -4
- data/lib/hexapdf/font/true_type_wrapper.rb +16 -16
- data/lib/hexapdf/font/type1_wrapper.rb +16 -16
- data/lib/hexapdf/font_loader.rb +2 -0
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -0
- data/lib/hexapdf/font_loader/standard14.rb +5 -0
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/layout/box.rb +2 -2
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/style.rb +50 -24
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +2 -2
- data/lib/hexapdf/layout/text_layouter.rb +14 -10
- data/lib/hexapdf/name_tree_node.rb +3 -3
- data/lib/hexapdf/number_tree_node.rb +3 -3
- data/lib/hexapdf/pdf_array.rb +207 -0
- data/lib/hexapdf/rectangle.rb +12 -12
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/stream.rb +6 -4
- data/lib/hexapdf/task/optimize.rb +3 -3
- data/lib/hexapdf/type.rb +2 -0
- data/lib/hexapdf/type/acro_form.rb +51 -0
- data/lib/hexapdf/type/acro_form/field.rb +129 -0
- data/lib/hexapdf/type/acro_form/form.rb +124 -0
- 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/annotation.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -0
- data/lib/hexapdf/type/annotations/link.rb +4 -15
- data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -1
- data/lib/hexapdf/type/annotations/text.rb +3 -6
- data/lib/hexapdf/type/annotations/widget.rb +90 -0
- data/lib/hexapdf/type/catalog.rb +12 -9
- data/lib/hexapdf/type/cid_font.rb +3 -3
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +5 -2
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +11 -6
- data/lib/hexapdf/type/icon_fit.rb +58 -0
- data/lib/hexapdf/type/image.rb +14 -8
- data/lib/hexapdf/type/info.rb +2 -1
- data/lib/hexapdf/type/page.rb +4 -4
- data/lib/hexapdf/type/page_tree_node.rb +3 -7
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +4 -4
- data/lib/hexapdf/type/viewer_preferences.rb +7 -4
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/man/man1/hexapdf.1 +77 -8
- data/test/hexapdf/content/test_canvas.rb +2 -2
- data/test/hexapdf/content/test_processor.rb +3 -3
- data/test/hexapdf/document/test_files.rb +4 -4
- data/test/hexapdf/document/test_fonts.rb +13 -1
- data/test/hexapdf/document/test_images.rb +6 -6
- data/test/hexapdf/document/test_pages.rb +8 -8
- data/test/hexapdf/encryption/test_security_handler.rb +7 -7
- data/test/hexapdf/encryption/test_standard_security_handler.rb +5 -5
- data/test/hexapdf/font/test_true_type_wrapper.rb +2 -2
- data/test/hexapdf/font_loader/test_from_configuration.rb +4 -0
- data/test/hexapdf/font_loader/test_standard14.rb +10 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
- data/test/hexapdf/image_loader/test_png.rb +3 -3
- data/test/hexapdf/layout/test_box.rb +2 -2
- data/test/hexapdf/layout/test_frame.rb +1 -1
- data/test/hexapdf/layout/test_image_box.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +18 -13
- data/test/hexapdf/layout/test_text_box.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +11 -6
- data/test/hexapdf/task/test_dereference.rb +2 -2
- data/test/hexapdf/task/test_optimize.rb +11 -11
- data/test/hexapdf/test_composer.rb +1 -1
- data/test/hexapdf/test_dictionary.rb +10 -2
- data/test/hexapdf/test_dictionary_fields.rb +27 -3
- data/test/hexapdf/test_document.rb +16 -15
- data/test/hexapdf/test_importer.rb +4 -4
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_pdf_array.rb +162 -0
- data/test/hexapdf/test_rectangle.rb +3 -5
- data/test/hexapdf/test_serializer.rb +1 -1
- data/test/hexapdf/test_stream.rb +1 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_field.rb +85 -0
- data/test/hexapdf/type/acro_form/test_form.rb +69 -0
- data/test/hexapdf/type/annotations/test_text.rb +2 -6
- data/test/hexapdf/type/annotations/test_widget.rb +24 -0
- data/test/hexapdf/type/test_annotation.rb +1 -1
- data/test/hexapdf/type/test_catalog.rb +1 -1
- data/test/hexapdf/type/test_cid_font.rb +3 -3
- data/test/hexapdf/type/test_font.rb +2 -2
- data/test/hexapdf/type/test_font_descriptor.rb +2 -1
- data/test/hexapdf/type/test_font_simple.rb +3 -3
- data/test/hexapdf/type/test_font_true_type.rb +6 -6
- data/test/hexapdf/type/test_font_type0.rb +5 -5
- data/test/hexapdf/type/test_font_type1.rb +8 -8
- data/test/hexapdf/type/test_font_type3.rb +4 -4
- data/test/hexapdf/type/test_image.rb +16 -12
- data/test/hexapdf/type/test_page.rb +11 -11
- data/test/hexapdf/type/test_page_tree_node.rb +20 -20
- data/test/hexapdf/type/test_resources.rb +6 -6
- data/test/hexapdf/type/test_trailer.rb +5 -2
- data/test/hexapdf/type/test_xref_stream.rb +1 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +35 -35
- metadata +23 -7
- data/test/hexapdf/type/annotations/test_link.rb +0 -19
@@ -60,9 +60,9 @@ module HexaPDF
|
|
60
60
|
|
61
61
|
include Utils::SortedTreeNode
|
62
62
|
|
63
|
-
define_field :Kids, type:
|
64
|
-
define_field :Names, type:
|
65
|
-
define_field :Limits, type:
|
63
|
+
define_field :Kids, type: PDFArray
|
64
|
+
define_field :Names, type: PDFArray
|
65
|
+
define_field :Limits, type: PDFArray
|
66
66
|
|
67
67
|
private
|
68
68
|
|
@@ -49,9 +49,9 @@ module HexaPDF
|
|
49
49
|
|
50
50
|
include Utils::SortedTreeNode
|
51
51
|
|
52
|
-
define_field :Kids, type:
|
53
|
-
define_field :Nums, type:
|
54
|
-
define_field :Limits, type:
|
52
|
+
define_field :Kids, type: PDFArray
|
53
|
+
define_field :Nums, type: PDFArray
|
54
|
+
define_field :Limits, type: PDFArray
|
55
55
|
|
56
56
|
private
|
57
57
|
|
@@ -0,0 +1,207 @@
|
|
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-2019 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/object'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
|
41
|
+
# Implementation of the PDF array type.
|
42
|
+
#
|
43
|
+
# This is mainly done to provide automatic resolution of indirect object references when using the
|
44
|
+
# #[] method. Therefore not all Array methods are implemented - use the #value directly if other
|
45
|
+
# methods are needed.
|
46
|
+
#
|
47
|
+
# See: PDF1.7 s7.3.6
|
48
|
+
class PDFArray < HexaPDF::Object
|
49
|
+
|
50
|
+
include Enumerable
|
51
|
+
|
52
|
+
# :call-seq:
|
53
|
+
# array[index] -> obj or nil
|
54
|
+
# array[start, length] -> new_array or nil
|
55
|
+
# array[range] -> new_array or nil
|
56
|
+
#
|
57
|
+
# Returns the value at the given index, or a subarray using the given +start+ and +length+, or a
|
58
|
+
# subarray specified by +range+.
|
59
|
+
#
|
60
|
+
# This method should be used instead of direct access to a value because it provides some
|
61
|
+
# advantages:
|
62
|
+
#
|
63
|
+
# * References are automatically resolved.
|
64
|
+
#
|
65
|
+
# * Returns the native Ruby object for values with class HexaPDF::Object. However, all
|
66
|
+
# subclasses of HexaPDF::Object are returned as is (it makes no sense, for example, to return
|
67
|
+
# the hash that describes the Catalog instead of the Catalog object).
|
68
|
+
def [](arg1, arg2 = nil)
|
69
|
+
data = value[arg1, *arg2]
|
70
|
+
return if data.nil?
|
71
|
+
|
72
|
+
if arg2 || arg1.kind_of?(Range)
|
73
|
+
index = (arg2 ? arg1 : arg1.begin)
|
74
|
+
data.map! {|item| process_entry(item, index).tap { index += 1 } }
|
75
|
+
else
|
76
|
+
process_entry(data, arg1)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Stores the data under the given index in the array.
|
81
|
+
#
|
82
|
+
# If the current value for this index has the class HexaPDF::Object (and only this, no
|
83
|
+
# subclasses) and the given data has not (including subclasses), the data is stored inside the
|
84
|
+
# HexaPDF::Object.
|
85
|
+
def []=(index, data)
|
86
|
+
if value[index].class == HexaPDF::Object && !data.kind_of?(HexaPDF::Object) &&
|
87
|
+
!data.kind_of?(HexaPDF::Reference)
|
88
|
+
value[index].value = data
|
89
|
+
else
|
90
|
+
value[index] = data
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the values at the given indices.
|
95
|
+
#
|
96
|
+
# See #[] for details
|
97
|
+
def values_at(*indices)
|
98
|
+
indices.map! {|index| self[index] }
|
99
|
+
end
|
100
|
+
|
101
|
+
# Append a value to the array.
|
102
|
+
def <<(data)
|
103
|
+
value << data
|
104
|
+
end
|
105
|
+
|
106
|
+
# Insert one or more values into the array at the given index.
|
107
|
+
def insert(index, *objects)
|
108
|
+
value.insert(index, *objects)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Deletes the value at the given index.
|
112
|
+
def delete_at(index)
|
113
|
+
value.delete_at(index)
|
114
|
+
end
|
115
|
+
|
116
|
+
# :call-seq:
|
117
|
+
# array.slice!(index) -> obj or nil
|
118
|
+
# array.slice!(start, length) -> new_array or nil
|
119
|
+
# array.slice!(range) -> new_array or nil
|
120
|
+
#
|
121
|
+
# Deletes the element(s) given by an index (and optionally a length) or by a range, and returns
|
122
|
+
# them or +nil+ if the index is out of range.
|
123
|
+
def slice!(arg1, arg2 = nil)
|
124
|
+
data = value.slice!(arg1, *arg2)
|
125
|
+
if arg2 || arg1.kind_of?(Range)
|
126
|
+
data.map! {|item| process_entry(item) }
|
127
|
+
else
|
128
|
+
process_entry(data)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# :call-seq:
|
133
|
+
# array.reject! {|item| block } -> array or nil
|
134
|
+
# array.reject! -> Enumerator
|
135
|
+
#
|
136
|
+
# Deletes all elements from the array for which the block returns +true+. If no changes were
|
137
|
+
# done, returns +nil+.
|
138
|
+
def reject!
|
139
|
+
value.reject! {|item| yield(process_entry(item)) }
|
140
|
+
end
|
141
|
+
|
142
|
+
# :call-seq:
|
143
|
+
# array.index(obj) -> int or nil
|
144
|
+
# array.index {|item| block } -> int or nil
|
145
|
+
# array.index -> Enumerator
|
146
|
+
#
|
147
|
+
# Returns the index of the first object such that object is == to +obj+, or, if a block is
|
148
|
+
# given, the index of the first object for which the block returns +true+.
|
149
|
+
def index(*obj, &block)
|
150
|
+
find_index(*obj, &block)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns the number of elements in the array.
|
154
|
+
def length
|
155
|
+
value.length
|
156
|
+
end
|
157
|
+
alias size length
|
158
|
+
|
159
|
+
# Returns +true+ if the array has no elements.
|
160
|
+
def empty?
|
161
|
+
value.empty?
|
162
|
+
end
|
163
|
+
|
164
|
+
# :call-seq:
|
165
|
+
# array.each {|value| block} -> array
|
166
|
+
# array.each -> Enumerator
|
167
|
+
#
|
168
|
+
# Calls the given block once for every value of the array.
|
169
|
+
#
|
170
|
+
# Note that the yielded value is already preprocessed like in #[].
|
171
|
+
def each
|
172
|
+
return to_enum(__method__) unless block_given?
|
173
|
+
value.each_index {|index| yield(self[index]) }
|
174
|
+
self
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns a duplicate of the underlying array.
|
178
|
+
def to_ary
|
179
|
+
value.dup
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
# Ensures that the value is useful for a PDFArray.
|
185
|
+
def after_data_change # :nodoc:
|
186
|
+
super
|
187
|
+
data.value ||= []
|
188
|
+
unless value.kind_of?(Array)
|
189
|
+
raise ArgumentError, "A PDF array object needs an array value, not a #{value.class}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Processes the given array entry with index +index+.
|
194
|
+
def process_entry(data, index = nil)
|
195
|
+
if data.kind_of?(HexaPDF::Reference)
|
196
|
+
data = document.deref(data)
|
197
|
+
value[index] = data if index
|
198
|
+
end
|
199
|
+
if data.class == HexaPDF::Object || (data.kind_of?(HexaPDF::Object) && data.value.nil?)
|
200
|
+
data = data.value
|
201
|
+
end
|
202
|
+
data
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
data/lib/hexapdf/rectangle.rb
CHANGED
@@ -34,7 +34,7 @@
|
|
34
34
|
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
35
35
|
#++
|
36
36
|
|
37
|
-
require 'hexapdf/
|
37
|
+
require 'hexapdf/pdf_array'
|
38
38
|
|
39
39
|
module HexaPDF
|
40
40
|
|
@@ -52,36 +52,36 @@ module HexaPDF
|
|
52
52
|
# is the top right x-coordinate and +top+ is the top right y-coordinate.
|
53
53
|
#
|
54
54
|
# See: PDF1.7 s7.9.5
|
55
|
-
class Rectangle < HexaPDF::
|
55
|
+
class Rectangle < HexaPDF::PDFArray
|
56
56
|
|
57
57
|
# Returns the x-coordinate of the bottom-left corner.
|
58
58
|
def left
|
59
|
-
|
59
|
+
self[0]
|
60
60
|
end
|
61
61
|
|
62
62
|
# Returns the x-coordinate of the top-right corner.
|
63
63
|
def right
|
64
|
-
|
64
|
+
self[2]
|
65
65
|
end
|
66
66
|
|
67
67
|
# Returns the y-coordinate of the bottom-left corner.
|
68
68
|
def bottom
|
69
|
-
|
69
|
+
self[1]
|
70
70
|
end
|
71
71
|
|
72
72
|
# Returns the y-coordinate of the top-right corner.
|
73
73
|
def top
|
74
|
-
|
74
|
+
self[3]
|
75
75
|
end
|
76
76
|
|
77
77
|
# Returns the width of the rectangle.
|
78
78
|
def width
|
79
|
-
|
79
|
+
self[2] - self[0]
|
80
80
|
end
|
81
81
|
|
82
82
|
# Returns the height of the rectangle.
|
83
83
|
def height
|
84
|
-
|
84
|
+
self[3] - self[1]
|
85
85
|
end
|
86
86
|
|
87
87
|
# Compares this rectangle to +other+ like in Object#== but also allows comparison to simple
|
@@ -96,16 +96,16 @@ module HexaPDF
|
|
96
96
|
# top right corner.
|
97
97
|
def after_data_change
|
98
98
|
super
|
99
|
-
unless value.
|
99
|
+
unless value.size == 4 && all?(Numeric)
|
100
100
|
raise ArgumentError, "A PDF rectangle structure must contain an array of four numbers"
|
101
101
|
end
|
102
|
-
|
103
|
-
|
102
|
+
self[0], self[2] = self[2], self[0] if self[0] > self[2]
|
103
|
+
self[1], self[3] = self[3], self[1] if self[1] > self[3]
|
104
104
|
end
|
105
105
|
|
106
106
|
def perform_validation #:nodoc:
|
107
107
|
super
|
108
|
-
unless value.
|
108
|
+
unless value.size == 4 && all?(Numeric)
|
109
109
|
yield("A PDF rectangle structure must contain an array of four numbers", false)
|
110
110
|
end
|
111
111
|
end
|
data/lib/hexapdf/serializer.rb
CHANGED
data/lib/hexapdf/stream.rb
CHANGED
@@ -132,15 +132,17 @@ module HexaPDF
|
|
132
132
|
# The basic Object class cannot hold stream data, only this subclass contains the necessary
|
133
133
|
# methods to conveniently work with the stream data!
|
134
134
|
#
|
135
|
+
# Note that support for external streams (/F, /FFilter, /FDecodeParms) is not yet implemented!
|
136
|
+
#
|
135
137
|
# See: PDF1.7 s7.3.8, Dictionary
|
136
138
|
class Stream < Dictionary
|
137
139
|
|
138
140
|
define_field :Length, type: Integer # not required, will be auto-filled when writing
|
139
|
-
define_field :Filter, type: [Symbol,
|
140
|
-
define_field :DecodeParms, type: [Dictionary,
|
141
|
+
define_field :Filter, type: [Symbol, PDFArray]
|
142
|
+
define_field :DecodeParms, type: [Dictionary, PDFArray]
|
141
143
|
define_field :F, type: :Filespec, version: '1.2'
|
142
|
-
define_field :FFilter, type: [Symbol,
|
143
|
-
define_field :FDecodeParms, type: [Dictionary,
|
144
|
+
define_field :FFilter, type: [Symbol, PDFArray], version: '1.2'
|
145
|
+
define_field :FDecodeParms, type: [Dictionary, PDFArray], version: '1.2'
|
144
146
|
define_field :DL, type: Integer
|
145
147
|
|
146
148
|
# Stream objects must always be indirect.
|
@@ -115,7 +115,7 @@ module HexaPDF
|
|
115
115
|
if object_streams == :generate
|
116
116
|
process_object_streams(doc, :generate, xref_streams)
|
117
117
|
elsif xref_streams == :generate
|
118
|
-
doc.add(Type: :XRef)
|
118
|
+
doc.add({Type: :XRef})
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
@@ -142,7 +142,7 @@ module HexaPDF
|
|
142
142
|
doc.revisions.each_with_index do |rev, rev_index|
|
143
143
|
xref_stream = false
|
144
144
|
count = 0
|
145
|
-
objstms = [doc.wrap(Type: :ObjStm)]
|
145
|
+
objstms = [doc.wrap({Type: :ObjStm})]
|
146
146
|
rev.each do |obj|
|
147
147
|
if obj.type == :XRef
|
148
148
|
xref_stream = true
|
@@ -156,7 +156,7 @@ module HexaPDF
|
|
156
156
|
objstms[-1].add_object(obj)
|
157
157
|
count += 1
|
158
158
|
if count == 200
|
159
|
-
objstms << doc.wrap(Type: :ObjStm)
|
159
|
+
objstms << doc.wrap({Type: :ObjStm})
|
160
160
|
count = 0
|
161
161
|
end
|
162
162
|
end
|
data/lib/hexapdf/type.rb
CHANGED
@@ -70,6 +70,8 @@ module HexaPDF
|
|
70
70
|
autoload(:FontType0, 'hexapdf/type/font_type0')
|
71
71
|
autoload(:CIDFont, 'hexapdf/type/cid_font')
|
72
72
|
autoload(:FontType3, 'hexapdf/type/font_type3')
|
73
|
+
autoload(:IconFit, 'hexapdf/type/icon_fit')
|
74
|
+
autoload(:AcroForm, 'hexapdf/type/acro_form')
|
73
75
|
|
74
76
|
end
|
75
77
|
|
@@ -0,0 +1,51 @@
|
|
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-2019 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
|
+
module HexaPDF
|
38
|
+
module Type
|
39
|
+
|
40
|
+
# Namespace module for all AcroForm related dictionary types.
|
41
|
+
#
|
42
|
+
# See: PDF1.7 s12.7
|
43
|
+
module AcroForm
|
44
|
+
|
45
|
+
autoload(:Form, 'hexapdf/type/acro_form/form')
|
46
|
+
autoload(:Field, 'hexapdf/type/acro_form/field')
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,129 @@
|
|
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-2019 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
|
+
module AcroForm
|
42
|
+
|
43
|
+
# Field dictionaries are used to define the properties of form fields of AcroForm objects.
|
44
|
+
#
|
45
|
+
# Fields can be organized in a hierarchy using the /Kids and /Parent keys, for namespacing
|
46
|
+
# purposes and to set default values. Those fields that have other fields as children are
|
47
|
+
# called non-terminal fields, otherwise they are called terminal fields.
|
48
|
+
#
|
49
|
+
# See: PDF1.7 s12.7.3.1
|
50
|
+
class Field < Dictionary
|
51
|
+
|
52
|
+
define_type :XXAcroFormField
|
53
|
+
|
54
|
+
# List of inheritable fields.
|
55
|
+
INHERITABLE_FIELDS = [:FT, :Ff, :V, :DV]
|
56
|
+
|
57
|
+
define_field :FT, type: Symbol, allowed_values: [:Btn, :Tx, :Ch, :Sig]
|
58
|
+
define_field :Parent, type: :XXAcroFormField
|
59
|
+
define_field :Kids, type: PDFArray
|
60
|
+
define_field :T, type: String
|
61
|
+
define_field :TU, type: String, version: '1.3'
|
62
|
+
define_field :TM, type: String, version: '1.3'
|
63
|
+
define_field :Ff, type: Integer, default: 0
|
64
|
+
define_field :V, type: [Symbol, String, Stream, PDFArray, Dictionary]
|
65
|
+
define_field :DV, type: [Symbol, String, Stream, PDFArray, Dictionary]
|
66
|
+
define_field :AA, type: Dictionary, version: '1.2'
|
67
|
+
|
68
|
+
# Form fields must always be indirect objects.
|
69
|
+
def must_be_indirect?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the value for the entry +name+.
|
74
|
+
#
|
75
|
+
# If +name+ is an inheritable value and the value has not been set on this field object, its
|
76
|
+
# value is retrieved from the parent fields.
|
77
|
+
#
|
78
|
+
# See: Dictionary#[]
|
79
|
+
def [](name)
|
80
|
+
if value[name].nil? && INHERITABLE_FIELDS.include?(name)
|
81
|
+
field = self
|
82
|
+
field = field[:Parent] while field.value[name].nil? && field[:Parent]
|
83
|
+
field == self || field.value[name].nil? ? super : field[name]
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns the type of the field, either :Btn (pushbuttons, check boxes, radio buttons), :Tx
|
90
|
+
# (text fields), :Ch (scrollable list boxes, combo boxes) or :Sig (signature fields).
|
91
|
+
def field_type
|
92
|
+
self[:FT]
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the full name of the field or +nil+ if no name is set.
|
96
|
+
#
|
97
|
+
# The full name of a field is constructed using the full name of the parent field, a period
|
98
|
+
# and the partial name of the field.
|
99
|
+
def full_name
|
100
|
+
if key?(:Parent)
|
101
|
+
[self[:Parent].full_name, self[:T]].compact.join('.')
|
102
|
+
else
|
103
|
+
self[:T]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns +true+ if this is a terminal field.
|
108
|
+
def terminal_field?
|
109
|
+
kids = self[:Kids]
|
110
|
+
kids.nil? || kids.empty? || kids.any? {|kid| kid[:Subtype] == :Widget }
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def perform_validation #:nodoc:
|
116
|
+
super
|
117
|
+
if terminal_field? && field_type.nil?
|
118
|
+
yield("/FT is required for terminal fields")
|
119
|
+
end
|
120
|
+
if key?(:T) && self[:T].include?('.')
|
121
|
+
yield("/T shall not contain a period")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|