hexapdf 0.45.0 → 0.46.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 +87 -47
- data/examples/019-acro_form.rb +5 -0
- data/lib/hexapdf/cli/inspect.rb +5 -0
- data/lib/hexapdf/composer.rb +1 -1
- data/lib/hexapdf/configuration.rb +8 -0
- data/lib/hexapdf/digital_signature/cms_handler.rb +31 -3
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +9 -1
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +5 -1
- data/lib/hexapdf/document/layout.rb +48 -27
- data/lib/hexapdf/document.rb +24 -2
- data/lib/hexapdf/importer.rb +15 -5
- data/lib/hexapdf/layout/box.rb +25 -28
- data/lib/hexapdf/layout/frame.rb +1 -1
- data/lib/hexapdf/layout/inline_box.rb +17 -23
- data/lib/hexapdf/layout/list_box.rb +24 -29
- data/lib/hexapdf/layout/page_style.rb +23 -16
- data/lib/hexapdf/layout/style.rb +2 -2
- data/lib/hexapdf/layout/text_box.rb +2 -6
- data/lib/hexapdf/parser.rb +5 -1
- data/lib/hexapdf/revisions.rb +1 -1
- data/lib/hexapdf/stream.rb +3 -3
- data/lib/hexapdf/tokenizer.rb +3 -2
- data/lib/hexapdf/type/acro_form/button_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/choice_field.rb +2 -0
- data/lib/hexapdf/type/acro_form/field.rb +8 -0
- data/lib/hexapdf/type/acro_form/form.rb +2 -1
- data/lib/hexapdf/type/acro_form/text_field.rb +2 -0
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/digital_signature/common.rb +66 -84
- data/test/hexapdf/digital_signature/signing/test_default_handler.rb +7 -0
- data/test/hexapdf/digital_signature/signing/test_signed_data_creator.rb +9 -0
- data/test/hexapdf/digital_signature/test_cms_handler.rb +41 -1
- data/test/hexapdf/digital_signature/test_handler.rb +2 -1
- data/test/hexapdf/document/test_layout.rb +28 -5
- data/test/hexapdf/layout/test_box.rb +12 -5
- data/test/hexapdf/layout/test_frame.rb +12 -2
- data/test/hexapdf/layout/test_inline_box.rb +17 -28
- data/test/hexapdf/layout/test_list_box.rb +5 -5
- data/test/hexapdf/layout/test_page_style.rb +7 -2
- data/test/hexapdf/layout/test_text_box.rb +3 -9
- data/test/hexapdf/layout/test_text_layouter.rb +0 -3
- data/test/hexapdf/test_document.rb +27 -0
- data/test/hexapdf/test_importer.rb +17 -0
- data/test/hexapdf/test_revisions.rb +54 -41
- data/test/hexapdf/type/acro_form/test_form.rb +9 -0
- metadata +2 -2
data/lib/hexapdf/document.rb
CHANGED
@@ -278,8 +278,9 @@ module HexaPDF
|
|
278
278
|
# If the same argument is provided in multiple invocations, the import is done only once and
|
279
279
|
# the previously imported object is returned.
|
280
280
|
#
|
281
|
-
# Note: If you first create a PDF document from scratch
|
282
|
-
# into another PDF document, you need to run the
|
281
|
+
# Note: If you first create a PDF document from scratch or if you modify an existing document,
|
282
|
+
# and then want to import objects from it into another PDF document, you need to run the
|
283
|
+
# following on the source document:
|
283
284
|
#
|
284
285
|
# doc.dispatch_message(:complete_objects)
|
285
286
|
# doc.validate
|
@@ -701,6 +702,27 @@ module HexaPDF
|
|
701
702
|
result
|
702
703
|
end
|
703
704
|
|
705
|
+
# Returns an in-memory copy of the PDF document.
|
706
|
+
#
|
707
|
+
# In the context of this method this means that the returned PDF document contains the same PDF
|
708
|
+
# object tree as this document, starting at the trailer. A possibly set encryption is not
|
709
|
+
# transferred to the returned document.
|
710
|
+
#
|
711
|
+
# Note: If this PDF document was created from scratch or if it is an existing document that was
|
712
|
+
# modified, the following commands need to be run on this document beforehand:
|
713
|
+
#
|
714
|
+
# doc.dispatch_message(:complete_objects)
|
715
|
+
# doc.validate
|
716
|
+
#
|
717
|
+
# This ensures that all the necessary PDF structures set-up correctly.
|
718
|
+
def duplicate
|
719
|
+
dest = HexaPDF::Document.new
|
720
|
+
dupped_trailer = HexaPDF::Importer.copy(dest, trailer, allow_all: true)
|
721
|
+
dest.revisions.current.trailer.value.replace(dupped_trailer.value)
|
722
|
+
dest.trailer.delete(:Encrypt)
|
723
|
+
dest
|
724
|
+
end
|
725
|
+
|
704
726
|
# :call-seq:
|
705
727
|
# doc.write(filename, incremental: false, validate: true, update_fields: true, optimize: false)
|
706
728
|
# doc.write(io, incremental: false, validate: true, update_fields: true, optimize: false)
|
data/lib/hexapdf/importer.rb
CHANGED
@@ -71,14 +71,18 @@ module HexaPDF
|
|
71
71
|
# Imports the given +object+ (belonging to the +source+ document) by completely copying it and
|
72
72
|
# all referenced objects into the +destination+ object.
|
73
73
|
#
|
74
|
+
# If the +allow_all+ argument is set to +true+, then the usually omitted catalog and page tree
|
75
|
+
# node objects (see the class description for details) are also copied which allows one to make
|
76
|
+
# an in-memory duplicate of a HexaPDF::Document object.
|
77
|
+
#
|
74
78
|
# Specifying +source+ is optionial if it can be determined through +object+.
|
75
79
|
#
|
76
80
|
# After the operation is finished, all state is discarded. This means that another call to this
|
77
81
|
# method for the same object will yield a new - and different - object. This is in contrast to
|
78
82
|
# using ::for together with #import which remembers and returns already imported objects (which
|
79
83
|
# is generally what one wants).
|
80
|
-
def self.copy(destination, object, source: nil)
|
81
|
-
new(NullableWeakRef.new(destination)).import(object, source: source)
|
84
|
+
def self.copy(destination, object, allow_all: false, source: nil)
|
85
|
+
new(NullableWeakRef.new(destination), allow_all: allow_all).import(object, source: source)
|
82
86
|
end
|
83
87
|
|
84
88
|
private_class_method :new
|
@@ -86,9 +90,10 @@ module HexaPDF
|
|
86
90
|
attr_reader :destination #:nodoc:
|
87
91
|
|
88
92
|
# Initializes a new importer that can import objects to the +destination+ document.
|
89
|
-
def initialize(destination)
|
93
|
+
def initialize(destination, allow_all: false)
|
90
94
|
@destination = destination
|
91
95
|
@mapper = {}
|
96
|
+
@allow_all = allow_all
|
92
97
|
end
|
93
98
|
|
94
99
|
SourceWrapper = Struct.new(:source) #:nodoc:
|
@@ -136,7 +141,7 @@ module HexaPDF
|
|
136
141
|
internal_import(wrapper.source.object(object), wrapper)
|
137
142
|
when HexaPDF::Object
|
138
143
|
wrapper.source ||= object.document
|
139
|
-
if object.type == :Catalog || object.type == :Pages
|
144
|
+
if !@allow_all && (object.type == :Catalog || object.type == :Pages)
|
140
145
|
@mapper[object.data] = nil
|
141
146
|
elsif (mapped_object = @mapper[object.data]&.__getobj__) && !mapped_object.null?
|
142
147
|
mapped_object
|
@@ -149,7 +154,12 @@ module HexaPDF
|
|
149
154
|
obj.data.gen = 0
|
150
155
|
@destination.add(obj) if object.indirect?
|
151
156
|
|
152
|
-
|
157
|
+
stream = obj.data.stream
|
158
|
+
if stream.kind_of?(String)
|
159
|
+
obj.data.stream = stream.dup
|
160
|
+
elsif stream&.source.kind_of?(FiberDoubleForString)
|
161
|
+
obj.data.stream = stream.fiber.resume.dup
|
162
|
+
end
|
153
163
|
obj.data.value = duplicate(obj.data.value, wrapper)
|
154
164
|
obj.data.value.update(duplicate(object.copy_inherited_values, wrapper)) if object.type == :Page
|
155
165
|
obj
|
data/lib/hexapdf/layout/box.rb
CHANGED
@@ -69,6 +69,10 @@ module HexaPDF
|
|
69
69
|
# If the subclass supports the value :flow of the 'position' style property, this method
|
70
70
|
# needs to be overridden to return +true+.
|
71
71
|
#
|
72
|
+
# Additionally, if a box object uses flow positioning, #fit_result.x should be set to the
|
73
|
+
# correct value since Frame#fit can't determine this and uses Frame#left in the absence of a
|
74
|
+
# set value.
|
75
|
+
#
|
72
76
|
# #empty?::
|
73
77
|
# This method should return +true+ if the subclass won't draw anything when #draw is called.
|
74
78
|
#
|
@@ -89,28 +93,13 @@ module HexaPDF
|
|
89
93
|
# This method draws the box specific content and is called from #draw which already handles
|
90
94
|
# things like drawing the border and background. So #draw should usually not be overridden.
|
91
95
|
#
|
92
|
-
# This base class provides various
|
93
|
-
#
|
94
|
-
# +reserved_width+, +reserved_height+::
|
95
|
-
# Returns the width respectively the height of the reserved space inside the box that is
|
96
|
-
# used for the border and padding.
|
97
|
-
#
|
98
|
-
# +reserved_width_left+, +reserved_width_right+, +reserved_height_top+,
|
99
|
-
# +reserved_height_bottom+::
|
100
|
-
# Returns the reserved space inside the box at the specified edge (left, right, top,
|
101
|
-
# bottom).
|
102
|
-
#
|
103
|
-
# +update_content_width+, +update_content_height+::
|
104
|
-
# Takes a block that should return the content width respectively height and sets the box's
|
105
|
-
# width respectively height accordingly.
|
106
|
-
#
|
107
|
-
# +create_split_box+::
|
108
|
-
# Creates a new box based on this one and resets the internal data back to their original
|
109
|
-
# values.
|
96
|
+
# This base class also provides various protected helper methods for use in the above methods:
|
110
97
|
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
98
|
+
# * #reserved_width, #reserved_height
|
99
|
+
# * #reserved_width_left, #reserved_width_right, #reserved_height_top,
|
100
|
+
# #reserved_height_bottom
|
101
|
+
# * #update_content_width, #update_content_height
|
102
|
+
# * #create_split_box
|
114
103
|
class Box
|
115
104
|
|
116
105
|
include HexaPDF::Utils
|
@@ -352,7 +341,9 @@ module HexaPDF
|
|
352
341
|
available_height
|
353
342
|
end
|
354
343
|
return @fit_result if !position_flow && (float_compare(@width, available_width) > 0 ||
|
355
|
-
float_compare(@height, available_height) > 0
|
344
|
+
float_compare(@height, available_height) > 0 ||
|
345
|
+
@width - reserved_width < 0 ||
|
346
|
+
@height - reserved_height < 0)
|
356
347
|
|
357
348
|
fit_content(available_width, available_height, frame)
|
358
349
|
|
@@ -432,7 +423,7 @@ module HexaPDF
|
|
432
423
|
(style.overlays? && !style.overlays.none?))
|
433
424
|
end
|
434
425
|
|
435
|
-
|
426
|
+
protected
|
436
427
|
|
437
428
|
# Returns the width that is reserved by the padding and border style properties.
|
438
429
|
def reserved_width
|
@@ -480,12 +471,18 @@ module HexaPDF
|
|
480
471
|
result
|
481
472
|
end
|
482
473
|
|
474
|
+
# :call-seq:
|
475
|
+
# update_content_width { block }
|
476
|
+
#
|
483
477
|
# Updates the width of the box using the content width returned by the block.
|
484
478
|
def update_content_width
|
485
479
|
return if @initial_width > 0
|
486
480
|
@width = yield + reserved_width
|
487
481
|
end
|
488
482
|
|
483
|
+
# :call-seq:
|
484
|
+
# update_content_height { block }
|
485
|
+
#
|
489
486
|
# Updates the height of the box using the content height returned by the block.
|
490
487
|
def update_content_height
|
491
488
|
return if @initial_height > 0
|
@@ -494,13 +491,12 @@ module HexaPDF
|
|
494
491
|
|
495
492
|
# Fits the content of the box and returns whether fitting was successful.
|
496
493
|
#
|
497
|
-
# This is just a stub implementation that sets the #fit_result status to success
|
498
|
-
#
|
499
|
-
# specific behaviour.
|
494
|
+
# This is just a stub implementation that sets the #fit_result status to success. Subclasses
|
495
|
+
# should override it to provide the box specific behaviour.
|
500
496
|
#
|
501
497
|
# See #fit for details.
|
502
498
|
def fit_content(_available_width, _available_height, _frame)
|
503
|
-
fit_result.success!
|
499
|
+
fit_result.success!
|
504
500
|
end
|
505
501
|
|
506
502
|
# Splits the content of the box.
|
@@ -525,7 +521,8 @@ module HexaPDF
|
|
525
521
|
end
|
526
522
|
end
|
527
523
|
|
528
|
-
# Creates a new box based on this one and resets the data back to their original
|
524
|
+
# Creates a new box based on this one and resets the internal data back to their original
|
525
|
+
# values.
|
529
526
|
#
|
530
527
|
# The variable +@split_box+ is set to +split_box_value+ (defaults to +true+) to make the new
|
531
528
|
# box aware that it is a split box. If needed, subclasses can set the variable to other truthy
|
data/lib/hexapdf/layout/frame.rb
CHANGED
@@ -43,14 +43,12 @@ module HexaPDF
|
|
43
43
|
# An InlineBox wraps a regular Box so that it can be used as an item for a Line. This enables
|
44
44
|
# inline graphics.
|
45
45
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
46
|
+
# When an inline box gets placed on a line, the method #fit_wrapped_box is called to fit the
|
47
|
+
# wrapped box. This allows the wrapped box to correctly set its width and height which are
|
48
|
+
# needed by the TextLayouter algorithm.
|
49
49
|
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# wrapped box and its height, or if not set, a practically infinite height. In the latter case
|
53
|
-
# the height *must* be set during fitting.
|
50
|
+
# Note: It is *mandatory* that the wrapped box sets its width and height without relying on the
|
51
|
+
# dimensions of the frame's current region.
|
54
52
|
class InlineBox
|
55
53
|
|
56
54
|
# Creates an InlineBox that wraps a basic Box. All arguments (except +valign+) and the block
|
@@ -74,7 +72,6 @@ module HexaPDF
|
|
74
72
|
# The +valign+ argument can be used to specify the vertical alignment of the box relative to
|
75
73
|
# other items in the Line.
|
76
74
|
def initialize(box, valign: :baseline)
|
77
|
-
raise HexaPDF::Error, "Width of box not set" if box.width == 0
|
78
75
|
@box = box
|
79
76
|
@valign = valign
|
80
77
|
end
|
@@ -102,8 +99,7 @@ module HexaPDF
|
|
102
99
|
# Draws the wrapped box. If the box has margins specified, the x and y offsets are correctly
|
103
100
|
# adjusted.
|
104
101
|
def draw(canvas, x, y)
|
105
|
-
|
106
|
-
y - @fit_result.y + box.style.margin.bottom) { @fit_result.draw(canvas) }
|
102
|
+
@fit_result.draw(canvas, dx: x, dy: y)
|
107
103
|
end
|
108
104
|
|
109
105
|
# The minimum x-coordinate which is always 0.
|
@@ -129,19 +125,17 @@ module HexaPDF
|
|
129
125
|
# Fits the wrapped box.
|
130
126
|
#
|
131
127
|
# If the +frame+ argument is +nil+, a custom frame is created. Otherwise the given +frame+ is
|
132
|
-
# used for the fitting operation.
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
@fit_result =
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
raise HexaPDF::Error, "Box for inline use has no valid height set after fitting"
|
144
|
-
end
|
128
|
+
# used for creating an appropriate child frame for the fitting operation.
|
129
|
+
#
|
130
|
+
# After this operation the caller is responsible for checking the actual width and height of
|
131
|
+
# the inline box and whether it really fits.
|
132
|
+
def fit_wrapped_box(frame = nil)
|
133
|
+
@fit_result = box.fit(100_000, 100_000, frame || Frame.new(0, 0, 100_000, 100_000))
|
134
|
+
margin = box.style.margin if box.style.margin?
|
135
|
+
@fit_result.x = margin&.left.to_i
|
136
|
+
@fit_result.y = margin&.bottom.to_i
|
137
|
+
@fit_result.mask = Geom2D::Rectangle(0, 0, @fit_result.x + box.width + margin&.right.to_i,
|
138
|
+
@fit_result.y + box.height + margin&.top.to_i)
|
145
139
|
end
|
146
140
|
|
147
141
|
end
|
@@ -243,7 +243,7 @@ module HexaPDF
|
|
243
243
|
break if !box_fitter.success? || height <= 0
|
244
244
|
end
|
245
245
|
|
246
|
-
|
246
|
+
update_content_height { @results.sum(&:height) + (@results.count - 1) * item_spacing }
|
247
247
|
|
248
248
|
if @results.size == @children.size && @results.all? {|r| r.box_fitter.success? }
|
249
249
|
fit_result.success!
|
@@ -316,37 +316,32 @@ module HexaPDF
|
|
316
316
|
def item_marker_box(document, index)
|
317
317
|
return @marker_type.call(document, self, index) if @marker_type.kind_of?(Proc)
|
318
318
|
|
319
|
-
unless (
|
319
|
+
unless (items = @item_marker_items)
|
320
320
|
marker_style = {
|
321
|
-
|
322
|
-
|
321
|
+
font_size: style.font_size || 10,
|
322
|
+
fill_color: style.fill_color,
|
323
323
|
}
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
TextFragment.create(text, marker_style)
|
344
|
-
else
|
345
|
-
raise HexaPDF::Error, "Unknown list marker type #{@marker_type.inspect}"
|
346
|
-
end
|
347
|
-
@item_marker_fragment = fragment unless @marker_type == :decimal
|
324
|
+
marker_style[:font] = style.font if style.font?
|
325
|
+
items = case @marker_type
|
326
|
+
when :disc
|
327
|
+
document.layout.text_fragments("•", style: marker_style)
|
328
|
+
when :circle
|
329
|
+
document.layout.text_fragments("❍", style: marker_style,
|
330
|
+
font_size: style.font_size / 2.0,
|
331
|
+
text_rise: -style.font_size / 1.8)
|
332
|
+
when :square
|
333
|
+
document.layout.text_fragments("■", style: marker_style,
|
334
|
+
font_size: style.font_size / 2.0,
|
335
|
+
text_rise: -style.font_size / 1.8)
|
336
|
+
when :decimal
|
337
|
+
text = (@start_number + index).to_s << "."
|
338
|
+
document.layout.text_fragments(text, style: marker_style)
|
339
|
+
else
|
340
|
+
raise HexaPDF::Error, "Unknown list marker type #{@marker_type.inspect}"
|
341
|
+
end
|
342
|
+
@item_marker_items = items unless @marker_type == :decimal
|
348
343
|
end
|
349
|
-
TextBox.new(items:
|
344
|
+
TextBox.new(items: items, style: {text_align: :right, padding: [0, 5, 0, 0]})
|
350
345
|
end
|
351
346
|
|
352
347
|
# Draws the list items onto the canvas at position [x, y].
|
@@ -41,7 +41,10 @@ require 'hexapdf/layout/frame'
|
|
41
41
|
module HexaPDF
|
42
42
|
module Layout
|
43
43
|
|
44
|
-
# A PageStyle defines the
|
44
|
+
# A PageStyle defines the dimensions of a page, its initial look, the Frame for object placement
|
45
|
+
# and which page style should be used next.
|
46
|
+
#
|
47
|
+
# This class is used by HexaPDF::Composer to style the individual pages.
|
45
48
|
class PageStyle
|
46
49
|
|
47
50
|
# The page size.
|
@@ -65,14 +68,15 @@ module HexaPDF
|
|
65
68
|
# The callable object is given a canvas and the page style as arguments. It needs to draw the
|
66
69
|
# initial content of the page. Note that the graphics state of the canvas is *not* saved
|
67
70
|
# before executing the template code and restored afterwards. If this is needed, the object
|
68
|
-
# needs to do it itself.
|
71
|
+
# needs to do it itself. The #next_style attribute can optionally be set.
|
69
72
|
#
|
70
|
-
# Furthermore
|
71
|
-
#
|
73
|
+
# Furthermore, the callable object should set the #frame that defines the area on the page
|
74
|
+
# where content should be placed. The #create_frame method can be used for easily creating a
|
75
|
+
# rectangular frame.
|
72
76
|
#
|
73
77
|
# Example:
|
74
78
|
#
|
75
|
-
# page_style.template = lambda do |canvas, style
|
79
|
+
# page_style.template = lambda do |canvas, style|
|
76
80
|
# box = canvas.context.box
|
77
81
|
# canvas.fill_color("fd0") do
|
78
82
|
# canvas.rectangle(0, 0, box.width, box.height).fill
|
@@ -81,22 +85,24 @@ module HexaPDF
|
|
81
85
|
# end
|
82
86
|
attr_accessor :template
|
83
87
|
|
84
|
-
# The
|
85
|
-
# placed.
|
88
|
+
# The Frame object that defines the area for the last page created with #create_page where
|
89
|
+
# content should be placed.
|
86
90
|
#
|
87
|
-
# This
|
88
|
-
#
|
89
|
-
#
|
90
|
-
# is set during #create_page.
|
91
|
+
# This value is usually updated during execution of the #template. If the value is not
|
92
|
+
# updated, a frame covering the page except for a default margin on all sides is set during
|
93
|
+
# #create_page.
|
91
94
|
attr_accessor :frame
|
92
95
|
|
93
96
|
# Defines the name of the page style that should be used for the next page.
|
94
97
|
#
|
98
|
+
# Note that this value can be different each time a new page is created via #create_page.
|
99
|
+
#
|
95
100
|
# If this attribute is +nil+ (the default), it means that this style should be used again.
|
96
101
|
attr_accessor :next_style
|
97
102
|
|
98
103
|
# Creates a new page style instance for the given page size, orientation and next style
|
99
|
-
# values. If a block is given, it is used as template for defining the initial content
|
104
|
+
# values. If a block is given, it is used as #template for defining the initial content of a
|
105
|
+
# page.
|
100
106
|
#
|
101
107
|
# Example:
|
102
108
|
#
|
@@ -113,14 +119,15 @@ module HexaPDF
|
|
113
119
|
@next_style = next_style
|
114
120
|
end
|
115
121
|
|
116
|
-
# Creates a new page in the given document
|
122
|
+
# Creates a new page in the given document using this page style and returns it.
|
117
123
|
#
|
118
|
-
# If #frame has not
|
119
|
-
#
|
124
|
+
# If the #frame has not changed during execution of the #template, a default frame covering
|
125
|
+
# the whole page except a margin of 36 is assigned.
|
120
126
|
def create_page(document)
|
127
|
+
frame_before = @frame
|
121
128
|
page = document.pages.create(media_box: page_size, orientation: orientation)
|
122
129
|
template&.call(page.canvas, self)
|
123
|
-
self.frame
|
130
|
+
self.frame = create_frame(page, 36) if @frame.equal?(frame_before)
|
124
131
|
page
|
125
132
|
end
|
126
133
|
|
data/lib/hexapdf/layout/style.rb
CHANGED
@@ -1369,8 +1369,8 @@ module HexaPDF
|
|
1369
1369
|
# composer.text('Text underneath')
|
1370
1370
|
#
|
1371
1371
|
# :fill_frame_horizontal::
|
1372
|
-
# The mask covers the box including the margin around the box
|
1373
|
-
#
|
1372
|
+
# The mask covers the box including the margin around the box, the space to the left and
|
1373
|
+
# right in the frame and the space to the top of the current region.
|
1374
1374
|
#
|
1375
1375
|
# Examples:
|
1376
1376
|
#
|
@@ -106,11 +106,6 @@ module HexaPDF
|
|
106
106
|
true
|
107
107
|
end
|
108
108
|
|
109
|
-
# :nodoc:
|
110
|
-
def draw(canvas, x, y)
|
111
|
-
super(canvas, x + @x_offset, y)
|
112
|
-
end
|
113
|
-
|
114
109
|
# :nodoc:
|
115
110
|
def empty?
|
116
111
|
super && (!@result || @result.lines.empty?)
|
@@ -137,7 +132,8 @@ module HexaPDF
|
|
137
132
|
min_x = [min_x, line.x_offset].min
|
138
133
|
max_x = [max_x, line.x_offset + line.width].max
|
139
134
|
end
|
140
|
-
@width = (min_x.finite? ?
|
135
|
+
@width = (min_x.finite? ? max_x - min_x : 0) + reserved_width
|
136
|
+
fit_result.x = @x_offset = min_x
|
141
137
|
@height = @initial_height > 0 ? @initial_height : @result.height + reserved_height
|
142
138
|
else
|
143
139
|
@result = @tl.fit(@items, @width - reserved_width, @height - reserved_height,
|
data/lib/hexapdf/parser.rb
CHANGED
@@ -71,6 +71,10 @@ module HexaPDF
|
|
71
71
|
end
|
72
72
|
|
73
73
|
# Returns +true+ if the PDF file is a linearized file.
|
74
|
+
#
|
75
|
+
# Note: The method uses heuristics to determine whether a PDF file is linearized. In case of
|
76
|
+
# slightly invalid or damaged PDFs that HexaPDF can recover from it is possible that this method
|
77
|
+
# returns +true+ even though the PDF isn't actually linearized.
|
74
78
|
def linearized?
|
75
79
|
@linearized ||=
|
76
80
|
begin
|
@@ -293,7 +297,7 @@ module HexaPDF
|
|
293
297
|
next
|
294
298
|
elsif type == 'n'
|
295
299
|
if pos == 0 || gen > 65535
|
296
|
-
maybe_raise("Invalid in use cross-reference entry",
|
300
|
+
maybe_raise("Invalid in use cross-reference entry for object number #{oid}",
|
297
301
|
pos: @tokenizer.pos)
|
298
302
|
xref.add_free_entry(oid, gen)
|
299
303
|
else
|
data/lib/hexapdf/revisions.rb
CHANGED
@@ -97,7 +97,7 @@ module HexaPDF
|
|
97
97
|
merge_revision = offset
|
98
98
|
end
|
99
99
|
|
100
|
-
if merge_revision == offset
|
100
|
+
if merge_revision == offset && !revisions.empty?
|
101
101
|
xref_section.merge!(revisions.first.xref_section)
|
102
102
|
offset = trailer[:Prev] # Get possible next offset before overwriting trailer
|
103
103
|
trailer = revisions.first.trailer
|
data/lib/hexapdf/stream.rb
CHANGED
@@ -51,6 +51,9 @@ module HexaPDF
|
|
51
51
|
# normalized to arrays on assignment to ease further processing.
|
52
52
|
class StreamData
|
53
53
|
|
54
|
+
# The source.
|
55
|
+
attr_reader :source
|
56
|
+
|
54
57
|
# The filter(s) that need to be applied for getting the decoded stream data.
|
55
58
|
attr_reader :filter
|
56
59
|
|
@@ -110,9 +113,6 @@ module HexaPDF
|
|
110
113
|
|
111
114
|
protected
|
112
115
|
|
113
|
-
# The source.
|
114
|
-
attr_reader :source
|
115
|
-
|
116
116
|
# The optional offset into the bytes provided by source.
|
117
117
|
attr_reader :offset
|
118
118
|
|
data/lib/hexapdf/tokenizer.rb
CHANGED
@@ -82,6 +82,7 @@ module HexaPDF
|
|
82
82
|
# correctable situations are only raised if the return value of calling the object is +true+.
|
83
83
|
def initialize(io, on_correctable_error: nil)
|
84
84
|
@io = io
|
85
|
+
@io_chunk = String.new(''.b)
|
85
86
|
@ss = StringScanner.new(''.b)
|
86
87
|
@original_pos = -1
|
87
88
|
@on_correctable_error = on_correctable_error || proc { false }
|
@@ -439,9 +440,9 @@ module HexaPDF
|
|
439
440
|
@io.seek(@next_read_pos)
|
440
441
|
return false if @io.eof?
|
441
442
|
|
442
|
-
@ss << @io.read(8192)
|
443
|
+
@ss << @io.read(8192, @io_chunk)
|
443
444
|
if @ss.pos > 8192 && @ss.string.length > 16384
|
444
|
-
@ss.string.
|
445
|
+
@ss.string.replace(@ss.string.byteslice(8192..-1))
|
445
446
|
@ss.pos -= 8192
|
446
447
|
@original_pos += 8192
|
447
448
|
end
|
@@ -65,6 +65,8 @@ module HexaPDF
|
|
65
65
|
#
|
66
66
|
# == Type Specific Field Flags
|
67
67
|
#
|
68
|
+
# See the class description for Field for the general field flags.
|
69
|
+
#
|
68
70
|
# :no_toggle_to_off:: Only used with radio buttons fields. If this flag is set, one button
|
69
71
|
# needs to be selected at all times. Otherwise, clicking on the selected
|
70
72
|
# button deselects it.
|
@@ -51,6 +51,8 @@ module HexaPDF
|
|
51
51
|
#
|
52
52
|
# == Type Specific Field Flags
|
53
53
|
#
|
54
|
+
# See the class description for Field for the general field flags.
|
55
|
+
#
|
54
56
|
# :combo:: If set, the field represents a combo box.
|
55
57
|
#
|
56
58
|
# :edit:: If set, the combo box includes an editable text box for entering arbitrary values.
|
@@ -76,6 +76,8 @@ module HexaPDF
|
|
76
76
|
#
|
77
77
|
# :no_export:: The field should *not* be exported by a submit-form action.
|
78
78
|
#
|
79
|
+
# Also see the class description of the subclasses for additional, type specific field flags.
|
80
|
+
#
|
79
81
|
# == Field Type Implementation Notes
|
80
82
|
#
|
81
83
|
# If an AcroForm field type adds additional inheritable dictionary fields, it has to set the
|
@@ -124,6 +126,8 @@ module HexaPDF
|
|
124
126
|
#
|
125
127
|
# Returns an array of flag names representing the set bit flags.
|
126
128
|
#
|
129
|
+
# See the class description for a list of available flags.
|
130
|
+
#
|
127
131
|
|
128
132
|
##
|
129
133
|
# :method: flagged?
|
@@ -133,6 +137,8 @@ module HexaPDF
|
|
133
137
|
# Returns +true+ if the given flag is set. The argument can either be the flag name or the
|
134
138
|
# bit index.
|
135
139
|
#
|
140
|
+
# See the class description for a list of available flags.
|
141
|
+
#
|
136
142
|
|
137
143
|
##
|
138
144
|
# :method: flag
|
@@ -142,6 +148,8 @@ module HexaPDF
|
|
142
148
|
# Sets the given flags, given as flag names or bit indices. If +clear_existing+ is +true+,
|
143
149
|
# all prior flags will be cleared.
|
144
150
|
#
|
151
|
+
# See the class description for a list of available flags.
|
152
|
+
#
|
145
153
|
bit_field(:flags, {read_only: 0, required: 1, no_export: 2},
|
146
154
|
lister: "flags", getter: "flagged?", setter: "flag", unsetter: "unflag",
|
147
155
|
value_getter: "self[:Ff]", value_setter: "self[:Ff]")
|
@@ -388,13 +388,14 @@ module HexaPDF
|
|
388
388
|
page_annots = page[:Annots].to_a - to_delete
|
389
389
|
page[:Annots].value.replace(page_annots)
|
390
390
|
end
|
391
|
-
to_delete.each {|widget| document.delete(widget) }
|
392
391
|
|
393
392
|
if field[:Parent]
|
394
393
|
field[:Parent][:Kids].delete(field)
|
395
394
|
else
|
396
395
|
self[:Fields].delete(field)
|
397
396
|
end
|
397
|
+
|
398
|
+
to_delete.each {|widget| document.delete(widget) }
|
398
399
|
document.delete(field)
|
399
400
|
end
|
400
401
|
|
@@ -50,6 +50,8 @@ module HexaPDF
|
|
50
50
|
#
|
51
51
|
# == Type Specific Field Flags
|
52
52
|
#
|
53
|
+
# See the class description for Field for the general field flags.
|
54
|
+
#
|
53
55
|
# :multiline:: If set, the text field may contain multiple lines.
|
54
56
|
#
|
55
57
|
# :password:: The field is a password field. This changes the behaviour of the PDF reader
|