hexapdf 0.10.0 → 0.11.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 +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
|