hexapdf 0.26.1 → 0.26.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/lib/hexapdf/document/layout.rb +24 -9
- data/lib/hexapdf/layout/box.rb +9 -2
- data/lib/hexapdf/layout/line.rb +4 -3
- data/lib/hexapdf/layout/style.rb +12 -6
- data/lib/hexapdf/layout/text_fragment.rb +21 -1
- data/lib/hexapdf/layout/text_layouter.rb +15 -21
- data/lib/hexapdf/revision.rb +9 -2
- data/lib/hexapdf/type/object_stream.rb +6 -8
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/document/test_layout.rb +19 -3
- data/test/hexapdf/layout/test_box.rb +5 -0
- data/test/hexapdf/layout/test_line.rb +6 -4
- data/test/hexapdf/layout/test_style.rb +20 -7
- data/test/hexapdf/layout/test_text_fragment.rb +26 -1
- data/test/hexapdf/layout/test_text_layouter.rb +9 -6
- data/test/hexapdf/test_composer.rb +18 -142
- data/test/hexapdf/test_revision.rb +18 -3
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/test_object_stream.rb +6 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f7ff4db8b6417cf6f0101a2e72e2481571a40c9542713be82753376d58c047c
|
4
|
+
data.tar.gz: 0b62a42fe5b91bdd8f11c4c31105e560cd4cf2f27259a86b9fd07db2f2280d6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ef60dd2da6c1c233768e564c5afb9330fb07065a33f293a2fbca6c71b8948d2ab754b2c9383ed4a84400e944e98f6c5a3638bf0c970c2b819eb53a0e024a2ca
|
7
|
+
data.tar.gz: 9c0190529f0d25d9ec655bef27d25054b9bfb5dc2ec980742807e73e0eb953550033f5362249cad1ec83ff8e78a1f1ad91785614cecdbaed113ad6365a77ade5
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
## 0.26.2 - 2022-10-22
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Support for setting custom properties on [HexaPDF::Layout::Box] and
|
6
|
+
[HexaPDF::Layout::TextFragment]
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
|
10
|
+
* [HexaPDF::Layout::Style::LinkLayer] to use the 'link' custom box property if
|
11
|
+
no target is set
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
* [HexaPDF::Layout::Style::Layers] to allow named layers without options
|
16
|
+
* [HexaPDF::Revision#each_modified_object] to not yield signature objects
|
17
|
+
* [HexaPDF::Revision#each_modified_object] to force comparison of direct objects
|
18
|
+
* [HexaPDF::Type::ObjectStream] to work for encrypted documents again
|
19
|
+
|
20
|
+
|
1
21
|
## 0.26.1 - 2022-10-14
|
2
22
|
|
3
23
|
### Changed
|
@@ -249,6 +249,10 @@ module HexaPDF
|
|
249
249
|
# +style_properties+ are specified, the style is duplicated and the additional styles are
|
250
250
|
# applied.
|
251
251
|
#
|
252
|
+
# +properties+::
|
253
|
+
# This can be used to set custom properties on the created text box. See Box#properties
|
254
|
+
# for details and usage.
|
255
|
+
#
|
252
256
|
# +box_style+::
|
253
257
|
# Sometimes it is necessary for the box to have a different style than the text, e.g. when
|
254
258
|
# using overlays. In such a case use +box_style+ for specifiying the style of the box (a
|
@@ -266,11 +270,13 @@ module HexaPDF
|
|
266
270
|
# })
|
267
271
|
#
|
268
272
|
# See: #formatted_text_box, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
|
269
|
-
def text_box(text, width: 0, height: 0, style: nil, box_style: nil,
|
273
|
+
def text_box(text, width: 0, height: 0, style: nil, properties: nil, box_style: nil,
|
274
|
+
**style_properties)
|
270
275
|
style = retrieve_style(style, style_properties)
|
271
276
|
box_style = (box_style ? retrieve_style(box_style) : style)
|
272
277
|
box_class_for_name(:text).new(items: [HexaPDF::Layout::TextFragment.create(text, style)],
|
273
|
-
width: width, height: height,
|
278
|
+
width: width, height: height, properties: properties,
|
279
|
+
style: box_style)
|
274
280
|
end
|
275
281
|
|
276
282
|
# Creates a HexaPDF::Layout::TextBox like #text_box but allows parts of the text to be
|
@@ -294,7 +300,8 @@ module HexaPDF
|
|
294
300
|
# If any style properties are set, the used style is duplicated and the additional
|
295
301
|
# properties applied.
|
296
302
|
#
|
297
|
-
# See #text_box for details on +width+, +height+, +style+, +style_properties
|
303
|
+
# See #text_box for details on +width+, +height+, +style+, +style_properties+, +properties+
|
304
|
+
# and +box_style+.
|
298
305
|
#
|
299
306
|
# Examples:
|
300
307
|
#
|
@@ -305,7 +312,8 @@ module HexaPDF
|
|
305
312
|
# layout.formatted_text_box(["Some ", {text: "string", style: {font_size: 20}}])
|
306
313
|
#
|
307
314
|
# See: #text_box, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
|
308
|
-
def formatted_text_box(data, width: 0, height: 0, style: nil, box_style: nil,
|
315
|
+
def formatted_text_box(data, width: 0, height: 0, style: nil, properties: nil, box_style: nil,
|
316
|
+
**style_properties)
|
309
317
|
style = retrieve_style(style, style_properties)
|
310
318
|
box_style = (box_style ? retrieve_style(box_style) : style)
|
311
319
|
data.map! do |hash|
|
@@ -315,10 +323,15 @@ module HexaPDF
|
|
315
323
|
link = hash.delete(:link)
|
316
324
|
(hash[:overlays] ||= []) << [:link, {uri: link}] if link
|
317
325
|
text = hash.delete(:text) || link || ""
|
318
|
-
|
326
|
+
properties = hash.delete(:properties)
|
327
|
+
frag_style = retrieve_style(hash.delete(:style) || style, hash)
|
328
|
+
fragment = HexaPDF::Layout::TextFragment.create(text, frag_style)
|
329
|
+
fragment.properties.update(properties) if properties
|
330
|
+
fragment
|
319
331
|
end
|
320
332
|
end
|
321
|
-
box_class_for_name(:text).new(items: data, width: width, height: height,
|
333
|
+
box_class_for_name(:text).new(items: data, width: width, height: height,
|
334
|
+
properties: properties, style: box_style)
|
322
335
|
end
|
323
336
|
|
324
337
|
# Creates a HexaPDF::Layout::ImageBox for the given image.
|
@@ -326,7 +339,8 @@ module HexaPDF
|
|
326
339
|
# The +file+ argument can be anything that is accepted by HexaPDF::Document::Images#add or a
|
327
340
|
# HexaPDF::Type::Form object.
|
328
341
|
#
|
329
|
-
# See #text_box for details on +width+, +height+, +style+ and
|
342
|
+
# See #text_box for details on +width+, +height+, +style+, +style_properties+ and
|
343
|
+
# +properties+.
|
330
344
|
#
|
331
345
|
# Examples:
|
332
346
|
#
|
@@ -334,10 +348,11 @@ module HexaPDF
|
|
334
348
|
# layout.image_box(machu_picchu, height: 30)
|
335
349
|
#
|
336
350
|
# See: HexaPDF::Layout::ImageBox
|
337
|
-
def image_box(file, width: 0, height: 0, style: nil, **style_properties)
|
351
|
+
def image_box(file, width: 0, height: 0, properties: nil, style: nil, **style_properties)
|
338
352
|
style = retrieve_style(style, style_properties)
|
339
353
|
image = file.kind_of?(HexaPDF::Stream) ? file : @document.images.add(file)
|
340
|
-
box_class_for_name(:image).new(image: image, width: width, height: height,
|
354
|
+
box_class_for_name(:image).new(image: image, width: width, height: height,
|
355
|
+
properties: properties, style: style)
|
341
356
|
end
|
342
357
|
|
343
358
|
# :nodoc:
|
data/lib/hexapdf/layout/box.rb
CHANGED
@@ -116,8 +116,14 @@ module HexaPDF
|
|
116
116
|
# * Style#underlays
|
117
117
|
attr_reader :style
|
118
118
|
|
119
|
+
# Hash with custom properties. The keys should be strings and can be arbitrary.
|
120
|
+
#
|
121
|
+
# This can be used to store arbitrary information on boxes for later use. For example, a
|
122
|
+
# generic style layer could use one or more custom properties for its work.
|
123
|
+
attr_reader :properties
|
124
|
+
|
119
125
|
# :call-seq:
|
120
|
-
# Box.new(width: 0, height: 0, style: nil) {|canv, box| block} -> box
|
126
|
+
# Box.new(width: 0, height: 0, style: nil, properties: {}) {|canv, box| block} -> box
|
121
127
|
#
|
122
128
|
# Creates a new Box object with the given width and height that uses the provided block when
|
123
129
|
# it is asked to draw itself on a canvas (see #draw).
|
@@ -125,10 +131,11 @@ module HexaPDF
|
|
125
131
|
# Since the final location of the box is not known beforehand, the drawing operations inside
|
126
132
|
# the block should draw inside the rectangle (0, 0, content_width, content_height) - note that
|
127
133
|
# the width and height of the box may not be known beforehand.
|
128
|
-
def initialize(width: 0, height: 0, style: nil, &block)
|
134
|
+
def initialize(width: 0, height: 0, style: nil, properties: {}, &block)
|
129
135
|
@width = @initial_width = width
|
130
136
|
@height = @initial_height = height
|
131
137
|
@style = Style.create(style)
|
138
|
+
@properties = properties
|
132
139
|
@draw_block = block
|
133
140
|
@fit_successful = false
|
134
141
|
@split_box = false
|
data/lib/hexapdf/layout/line.rb
CHANGED
@@ -192,13 +192,14 @@ module HexaPDF
|
|
192
192
|
|
193
193
|
# Adds the given item at the end of the item list.
|
194
194
|
#
|
195
|
-
# If both the item and the last item in the item list are TextFragment objects
|
196
|
-
#
|
195
|
+
# If both the item and the last item in the item list are TextFragment objects with the same
|
196
|
+
# attributes, they are combined.
|
197
197
|
#
|
198
198
|
# Note: The cache is not cleared!
|
199
199
|
def add(item)
|
200
200
|
last = @items.last
|
201
|
-
if last.instance_of?(item.class) && item.kind_of?(TextFragment) &&
|
201
|
+
if last.instance_of?(item.class) && item.kind_of?(TextFragment) &&
|
202
|
+
last.attributes_hash == item.attributes_hash
|
202
203
|
if last.items.frozen?
|
203
204
|
@items[-1] = last = last.dup
|
204
205
|
last.items = last.items.dup
|
data/lib/hexapdf/layout/style.rb
CHANGED
@@ -382,8 +382,9 @@ module HexaPDF
|
|
382
382
|
class Layers
|
383
383
|
|
384
384
|
# Creates a new Layers object popuplated with the given +layers+.
|
385
|
-
def initialize(layers =
|
386
|
-
@layers =
|
385
|
+
def initialize(layers = nil)
|
386
|
+
@layers = []
|
387
|
+
layers&.each {|name, options| add(name, **(options || {})) }
|
387
388
|
end
|
388
389
|
|
389
390
|
# Duplicates the array holding the layers.
|
@@ -402,8 +403,8 @@ module HexaPDF
|
|
402
403
|
# object in 'style.layers_map'. In this case +name+ is used as the reference and the options
|
403
404
|
# are passed to layer object if it needs initialization.
|
404
405
|
def add(name = nil, **options, &block)
|
405
|
-
if block_given?
|
406
|
-
@layers << block
|
406
|
+
if block_given? || name.kind_of?(Proc)
|
407
|
+
@layers << (block || name)
|
407
408
|
elsif name
|
408
409
|
@layers << [name, options]
|
409
410
|
else
|
@@ -452,7 +453,9 @@ module HexaPDF
|
|
452
453
|
# be specified):
|
453
454
|
#
|
454
455
|
# +dest+::
|
455
|
-
# The destination array or a name of a named destination for in-document links.
|
456
|
+
# The destination array or a name of a named destination for in-document links. If neither
|
457
|
+
# +dest+ nor +uri+ nor +file+ is specified, it is assumed that the box has a custom
|
458
|
+
# property named 'link' which is used for the destination.
|
456
459
|
#
|
457
460
|
# +uri+::
|
458
461
|
# The URI to link to.
|
@@ -473,6 +476,7 @@ module HexaPDF
|
|
473
476
|
# Examples:
|
474
477
|
# LinkLayer.new(dest: [page, :XYZ, nil, nil, nil], border: true)
|
475
478
|
# LinkLayer.new(uri: "https://my.example.com/path", border: [5 5 2])
|
479
|
+
# LinkLayer.new # use 'link' custom box property for dest
|
476
480
|
def initialize(dest: nil, uri: nil, file: nil, border: false, border_color: nil)
|
477
481
|
if dest && (uri || file) || uri && file
|
478
482
|
raise ArgumentError, "Only one of dest, uri and file is allowed"
|
@@ -496,6 +500,8 @@ module HexaPDF
|
|
496
500
|
# page.
|
497
501
|
def call(canvas, box)
|
498
502
|
return unless canvas.context.type == :Page
|
503
|
+
@dest = box.properties['link'] unless @dest || @action
|
504
|
+
|
499
505
|
page = canvas.context
|
500
506
|
matrix = canvas.graphics_state.ctm
|
501
507
|
quad_points = [*matrix.evaluate(0, 0), *matrix.evaluate(box.width, 0),
|
@@ -554,7 +560,7 @@ module HexaPDF
|
|
554
560
|
# Duplicates the complex properties that can be modified, as well as the cache.
|
555
561
|
def initialize_copy(other)
|
556
562
|
super
|
557
|
-
@scaled_item_widths = {}
|
563
|
+
@scaled_item_widths = {}.compare_by_identity
|
558
564
|
clear_cache
|
559
565
|
|
560
566
|
@font_features = @font_features.dup if defined?(@font_features)
|
@@ -105,9 +105,29 @@ module HexaPDF
|
|
105
105
|
#
|
106
106
|
# The argument +style+ can either be a Style object or a hash of style properties, see
|
107
107
|
# Style::create for details.
|
108
|
-
def initialize(items, style)
|
108
|
+
def initialize(items, style, properties: nil)
|
109
109
|
@items = items
|
110
110
|
@style = Style.create(style)
|
111
|
+
@properties = properties
|
112
|
+
end
|
113
|
+
|
114
|
+
# Creates a new TextFragment with the same style and custom properties as this one but with
|
115
|
+
# the given +items+.
|
116
|
+
def dup_attributes(items)
|
117
|
+
self.class.new(items, @style, properties: @properties.dup)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns the custom properties hash for the text fragment.
|
121
|
+
#
|
122
|
+
# See Box#properties for usage details.
|
123
|
+
def properties
|
124
|
+
@properties ||= {}
|
125
|
+
end
|
126
|
+
|
127
|
+
# Returns the value that should be used as hash key when only the fragment's attributes -
|
128
|
+
# without the items - should play a role.
|
129
|
+
def attributes_hash
|
130
|
+
@style.hash ^ @properties.hash
|
111
131
|
end
|
112
132
|
|
113
133
|
# The precision used to determine whether two floats represent the same value.
|
@@ -243,43 +243,38 @@ module HexaPDF
|
|
243
243
|
box_items << glyph if glyph && !glyph.kind_of?(Numeric) && glyph.str == '-'
|
244
244
|
|
245
245
|
unless box_items.empty?
|
246
|
-
result << Box.new(
|
246
|
+
result << Box.new(item.dup_attributes(box_items.freeze))
|
247
247
|
end
|
248
248
|
|
249
249
|
if glyph
|
250
250
|
case glyph.str
|
251
251
|
when ' '
|
252
|
-
glues[item.
|
253
|
-
|
254
|
-
result << glues[item.style]
|
252
|
+
result << (glues[item.attributes_hash] ||=
|
253
|
+
Glue.new(item.dup_attributes([glyph].freeze)))
|
255
254
|
when "\n", "\v", "\f", "\u{85}", "\u{2029}"
|
256
|
-
penalties[item.
|
257
|
-
|
258
|
-
|
259
|
-
result << penalties[item.style]
|
255
|
+
result << (penalties[item.attributes_hash] ||=
|
256
|
+
Penalty.new(Penalty::PARAGRAPH_BREAK, 0,
|
257
|
+
item: item.dup_attributes([].freeze)))
|
260
258
|
when "\u{2028}"
|
261
259
|
result << Penalty.new(Penalty::LINE_BREAK, 0,
|
262
|
-
item:
|
260
|
+
item: item.dup_attributes([].freeze))
|
263
261
|
when "\r"
|
264
262
|
if !item.items[i + 1] || item.items[i + 1].kind_of?(Numeric) ||
|
265
263
|
item.items[i + 1].str != "\n"
|
266
|
-
penalties[item.
|
267
|
-
|
268
|
-
|
269
|
-
result << penalties[item.style]
|
264
|
+
result << (penalties[item.attributes_hash] ||=
|
265
|
+
Penalty.new(Penalty::PARAGRAPH_BREAK, 0,
|
266
|
+
item: item.dup_attributes([].freeze)))
|
270
267
|
end
|
271
268
|
when '-'
|
272
269
|
result << Penalty::Standard
|
273
270
|
when "\t"
|
274
271
|
spaces = [item.style.font.decode_utf8(" ").first] * 8
|
275
|
-
result << Glue.new(
|
272
|
+
result << Glue.new(item.dup_attributes(spaces.freeze))
|
276
273
|
when "\u{00AD}"
|
277
|
-
|
278
|
-
frag = TextFragment.new([hyphen].freeze, item.style)
|
274
|
+
frag = item.dup_attributes([item.style.font.decode_utf8("-").first].freeze)
|
279
275
|
result << Penalty.new(Penalty::Standard.penalty, frag.width, item: frag)
|
280
276
|
when "\u{00A0}"
|
281
|
-
|
282
|
-
frag = TextFragment.new([space].freeze, item.style)
|
277
|
+
frag = item.dup_attributes([item.style.font.decode_utf8(" ").first].freeze)
|
283
278
|
result << Penalty.new(Penalty::ProhibitedBreak.penalty, frag.width, item: frag)
|
284
279
|
when "\u{200B}"
|
285
280
|
result << Penalty.new(0)
|
@@ -835,7 +830,7 @@ module HexaPDF
|
|
835
830
|
if too_wide_box && (too_wide_box.item.kind_of?(TextFragment) &&
|
836
831
|
too_wide_box.item.items.size > 1)
|
837
832
|
rest[0..rest.index(too_wide_box)] = too_wide_box.item.items.map do |item|
|
838
|
-
Box.new(
|
833
|
+
Box.new(too_wide_box.item.dup_attributes([item].freeze))
|
839
834
|
end
|
840
835
|
too_wide_box = nil
|
841
836
|
else
|
@@ -939,8 +934,7 @@ module HexaPDF
|
|
939
934
|
frag = line.items[indexes[i]]
|
940
935
|
value = -frag.items[indexes[i + 1]].width * adjustment
|
941
936
|
if frag.items.frozen?
|
942
|
-
|
943
|
-
line.items.insert(indexes[i], value)
|
937
|
+
line.items.insert(indexes[i], frag.dup_attributes([value]))
|
944
938
|
else
|
945
939
|
frag.items.insert(indexes[i + 1], value)
|
946
940
|
frag.clear_cache
|
data/lib/hexapdf/revision.rb
CHANGED
@@ -243,14 +243,21 @@ module HexaPDF
|
|
243
243
|
@objects.each do |oid, gen, obj|
|
244
244
|
if @xref_section.entry?(oid, gen)
|
245
245
|
stored_obj = @loader.call(@xref_section[oid, gen])
|
246
|
-
next if (stored_obj.type == :ObjStm || stored_obj.type == :XRef) && obj.null?
|
246
|
+
next if (stored_obj.type == :ObjStm || stored_obj.type == :XRef) && obj.null? ||
|
247
|
+
stored_obj.type == :Sig || stored_obj.type == :DocTimeStamp
|
247
248
|
|
248
249
|
streams_are_same = (obj.data.stream == stored_obj.data.stream)
|
249
250
|
next if obj.value == stored_obj.value && streams_are_same
|
250
251
|
|
251
252
|
if obj.value.kind_of?(Hash) && stored_obj.value.kind_of?(Hash)
|
252
253
|
keys = obj.value.keys | stored_obj.value.keys
|
253
|
-
|
254
|
+
values_unchanged = keys.all? do |key|
|
255
|
+
other = stored_obj[key]
|
256
|
+
# Force comparison of values if both are indirect objects
|
257
|
+
other = other.value if other.kind_of?(Object) && !other.indirect?
|
258
|
+
obj[key] == other
|
259
|
+
end
|
260
|
+
next if values_unchanged && streams_are_same
|
254
261
|
end
|
255
262
|
end
|
256
263
|
|
@@ -203,13 +203,6 @@ module HexaPDF
|
|
203
203
|
|
204
204
|
private
|
205
205
|
|
206
|
-
# Parses the stream data after the object is first initialized. Since the parsed stream data
|
207
|
-
# is cached, it is only parsed on initialization and not again if e.g. the stream is changed.
|
208
|
-
def after_data_change
|
209
|
-
super
|
210
|
-
parse_stream
|
211
|
-
end
|
212
|
-
|
213
206
|
# Parses the object numbers and their offsets from the start of the stream data.
|
214
207
|
def parse_oids_and_offsets(data)
|
215
208
|
oids = []
|
@@ -227,7 +220,12 @@ module HexaPDF
|
|
227
220
|
|
228
221
|
# Returns the container with the to-be-stored objects.
|
229
222
|
def objects
|
230
|
-
@objects ||=
|
223
|
+
@objects ||=
|
224
|
+
begin
|
225
|
+
@objects = {}
|
226
|
+
parse_stream
|
227
|
+
@objects
|
228
|
+
end
|
231
229
|
end
|
232
230
|
|
233
231
|
# Validates that the generation number of the object stream is zero.
|
data/lib/hexapdf/version.rb
CHANGED
@@ -90,12 +90,14 @@ describe HexaPDF::Document::Layout do
|
|
90
90
|
|
91
91
|
describe "box" do
|
92
92
|
it "creates the request box" do
|
93
|
-
box = @layout.box(:column, columns: 3, gaps: 20, width: 15, height: 30, style: {font_size: 10}
|
93
|
+
box = @layout.box(:column, columns: 3, gaps: 20, width: 15, height: 30, style: {font_size: 10},
|
94
|
+
properties: {key: :value})
|
94
95
|
assert_equal(15, box.width)
|
95
96
|
assert_equal(30, box.height)
|
96
97
|
assert_equal([-1, -1, -1], box.columns)
|
97
98
|
assert_equal([20], box.gaps)
|
98
99
|
assert_equal(10, box.style.font_size)
|
100
|
+
assert_equal({key: :value}, box.properties)
|
99
101
|
end
|
100
102
|
|
101
103
|
it "allows specifying the box's children via a provided block" do
|
@@ -113,13 +115,14 @@ describe HexaPDF::Document::Layout do
|
|
113
115
|
|
114
116
|
describe "text_box" do
|
115
117
|
it "creates a text box" do
|
116
|
-
box = @layout.text_box("Test", width: 10, height: 15)
|
118
|
+
box = @layout.text_box("Test", width: 10, height: 15, properties: {key: :value})
|
117
119
|
assert_equal(10, box.width)
|
118
120
|
assert_equal(15, box.height)
|
119
121
|
assert_same(@doc.fonts.add("Times"), box.style.font)
|
120
122
|
items = box.instance_variable_get(:@items)
|
121
123
|
assert_equal(1, items.length)
|
122
124
|
assert_same(box.style, items.first.style)
|
125
|
+
assert_equal({key: :value}, box.properties)
|
123
126
|
end
|
124
127
|
|
125
128
|
it "allows setting of a custom style" do
|
@@ -162,6 +165,11 @@ describe HexaPDF::Document::Layout do
|
|
162
165
|
assert_equal(1, box.instance_variable_get(:@items).length)
|
163
166
|
end
|
164
167
|
|
168
|
+
it "allows setting custom properties on the whole box" do
|
169
|
+
box = @layout.formatted_text_box(["Test"], properties: {key: :value})
|
170
|
+
assert_equal({key: :value}, box.properties)
|
171
|
+
end
|
172
|
+
|
165
173
|
it "allows using a hash with :text key instead of a simple string" do
|
166
174
|
box = @layout.formatted_text_box([{text: "Test"}])
|
167
175
|
items = box.instance_variable_get(:@items)
|
@@ -218,18 +226,26 @@ describe HexaPDF::Document::Layout do
|
|
218
226
|
assert_equal([:link, {uri: 'URI'}], items[0].style.overlays.instance_variable_get(:@layers)[0])
|
219
227
|
refute(items[2].style.overlays?)
|
220
228
|
end
|
229
|
+
|
230
|
+
it "allows setting custom properties" do
|
231
|
+
box = @layout.formatted_text_box([{text: 'test', properties: {named_dest: 'test'}}])
|
232
|
+
items = box.instance_variable_get(:@items)
|
233
|
+
assert_equal({named_dest: 'test'}, items[0].properties)
|
234
|
+
end
|
221
235
|
end
|
222
236
|
|
223
237
|
describe "image_box" do
|
224
238
|
it "creates an image box" do
|
225
239
|
image_path = File.join(TEST_DATA_DIR, 'images', 'gray.jpg')
|
226
240
|
|
227
|
-
box = @layout.image_box(image_path, width: 10, height: 15, style: {font_size: 20},
|
241
|
+
box = @layout.image_box(image_path, width: 10, height: 15, style: {font_size: 20},
|
242
|
+
properties: {key: :value}, subscript: true)
|
228
243
|
assert_equal(10, box.width)
|
229
244
|
assert_equal(15, box.height)
|
230
245
|
assert_equal(20, box.style.font_size)
|
231
246
|
assert(box.style.subscript)
|
232
247
|
assert_same(@doc.images.add(image_path), box.image)
|
248
|
+
assert_equal({key: :value}, box.properties)
|
233
249
|
end
|
234
250
|
|
235
251
|
it "allows using a form XObject" do
|
@@ -54,6 +54,11 @@ describe HexaPDF::Layout::Box do
|
|
54
54
|
box = create_box(style: HexaPDF::Layout::Style.new(padding: 20))
|
55
55
|
assert_equal(20, box.style.padding.top)
|
56
56
|
end
|
57
|
+
|
58
|
+
it "allows setting custom properties" do
|
59
|
+
box = create_box(properties: {'key' => :value})
|
60
|
+
assert_equal({'key' => :value}, box.properties)
|
61
|
+
end
|
57
62
|
end
|
58
63
|
|
59
64
|
it "returns false when asking whether it is a split box by default" do
|
@@ -50,10 +50,12 @@ describe HexaPDF::Layout::Line do
|
|
50
50
|
|
51
51
|
it "combines text fragments if possible" do
|
52
52
|
frag1 = setup_fragment("Home")
|
53
|
-
frag2 = HexaPDF::Layout::TextFragment.new(frag1.items
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
frag2 = HexaPDF::Layout::TextFragment.new(frag1.items[2, 2], frag1.style)
|
54
|
+
frag3 = HexaPDF::Layout::TextFragment.new(frag1.items[2, 2], frag1.style,
|
55
|
+
properties: {'key' => :value})
|
56
|
+
@line << setup_fragment("o") << :other << frag1 << frag2 << frag3
|
57
|
+
assert_equal(4, @line.items.length)
|
58
|
+
assert_equal(6, @line.items[-2].items.length)
|
57
59
|
end
|
58
60
|
|
59
61
|
it "duplicates the first of two combinable text fragments if its items are frozen" do
|
@@ -448,12 +448,16 @@ end
|
|
448
448
|
describe HexaPDF::Layout::Style::Layers do
|
449
449
|
before do
|
450
450
|
@layers = HexaPDF::Layout::Style::Layers.new
|
451
|
+
value = Object.new
|
452
|
+
value.define_singleton_method(:new) {|*| :new }
|
453
|
+
@config = Object.new
|
454
|
+
@config.define_singleton_method(:constantize) {|*| value }
|
451
455
|
end
|
452
456
|
|
453
457
|
it "can be initialized with an array of layers" do
|
454
|
-
data = [lambda {}]
|
458
|
+
data = [lambda {}, [:test]]
|
455
459
|
layers = HexaPDF::Layout::Style::Layers.new(data)
|
456
|
-
assert_equal(data, layers.enum_for(:each,
|
460
|
+
assert_equal([data[0], :new], layers.enum_for(:each, @config).to_a)
|
457
461
|
end
|
458
462
|
|
459
463
|
it "can be duplicated" do
|
@@ -469,13 +473,15 @@ describe HexaPDF::Layout::Style::Layers do
|
|
469
473
|
assert_equal([block], @layers.enum_for(:each, {}).to_a)
|
470
474
|
end
|
471
475
|
|
476
|
+
it "can use a given proc" do
|
477
|
+
block = proc { true }
|
478
|
+
@layers.add(block)
|
479
|
+
assert_equal([block], @layers.enum_for(:each, {}).to_a)
|
480
|
+
end
|
481
|
+
|
472
482
|
it "can store a reference" do
|
473
483
|
@layers.add(:link, option: :value)
|
474
|
-
|
475
|
-
value.define_singleton_method(:new) {|*| :new }
|
476
|
-
config = Object.new
|
477
|
-
config.define_singleton_method(:constantize) {|*| value }
|
478
|
-
assert_equal([:new], @layers.enum_for(:each, config).to_a)
|
484
|
+
assert_equal([:new], @layers.enum_for(:each, @config).to_a)
|
479
485
|
end
|
480
486
|
|
481
487
|
it "fails if neither a block nor a name is given when adding a layer" do
|
@@ -590,6 +596,13 @@ describe HexaPDF::Layout::Style::LinkLayer do
|
|
590
596
|
assert_equal({S: :Launch, F: "local-file.pdf", NewWindow: true}, annot[:A].value)
|
591
597
|
assert_nil(annot[:Dest])
|
592
598
|
end
|
599
|
+
|
600
|
+
it "works for destinations set via the 'link' custom box property" do
|
601
|
+
@box.properties['link'] = [@canvas.context, :FitH]
|
602
|
+
annot = call_link({})
|
603
|
+
assert_equal([@canvas.context, :FitH], annot[:Dest].value)
|
604
|
+
assert_nil(annot[:A])
|
605
|
+
end
|
593
606
|
end
|
594
607
|
end
|
595
608
|
|
@@ -46,11 +46,36 @@ describe HexaPDF::Layout::TextFragment do
|
|
46
46
|
end
|
47
47
|
|
48
48
|
it "can use style options" do
|
49
|
-
frag = HexaPDF::Layout::TextFragment.new(@items, font: @font, font_size: 20)
|
49
|
+
frag = HexaPDF::Layout::TextFragment.new(@items, {font: @font, font_size: 20})
|
50
50
|
assert_equal(20, frag.style.font_size)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
it "allows duplicating with only its attributes while also setting new items" do
|
55
|
+
setup_fragment([20])
|
56
|
+
@fragment.properties['key'] = :value
|
57
|
+
frag = @fragment.dup_attributes([21])
|
58
|
+
assert_equal([21], frag.items)
|
59
|
+
assert_same(frag.style, @fragment.style)
|
60
|
+
assert_equal(:value, frag.properties['key'])
|
61
|
+
end
|
62
|
+
|
63
|
+
it "creates an attributes hash for storing the fragment based on the attributes without the items" do
|
64
|
+
setup_fragment([20])
|
65
|
+
hash = @fragment.attributes_hash
|
66
|
+
@fragment.properties['key'] = :value
|
67
|
+
new_hash = @fragment.attributes_hash
|
68
|
+
refute_equal(hash, new_hash)
|
69
|
+
@fragment.items << [21]
|
70
|
+
assert_equal(new_hash, @fragment.attributes_hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "allows setting custom properties" do
|
74
|
+
setup_fragment([])
|
75
|
+
@fragment.properties[:key] = :value
|
76
|
+
assert_equal({key: :value}, @fragment.properties)
|
77
|
+
end
|
78
|
+
|
54
79
|
it "returns :text for valign" do
|
55
80
|
assert_equal(:text, setup_fragment([]).valign)
|
56
81
|
end
|
@@ -31,12 +31,14 @@ module TestTextLayouterHelpers
|
|
31
31
|
else
|
32
32
|
assert_same(item.style, obj.item.style)
|
33
33
|
assert_equal(item.items, obj.item.items)
|
34
|
+
assert_equal(item.properties, obj.item.properties)
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
def assert_glue(obj, fragment)
|
38
39
|
assert_kind_of(HexaPDF::Layout::TextLayouter::Glue, obj)
|
39
40
|
assert_same(fragment.style, obj.item.style)
|
41
|
+
assert_equal(fragment.properties, obj.item.properties)
|
40
42
|
end
|
41
43
|
|
42
44
|
def assert_penalty(obj, penalty, item = nil)
|
@@ -45,6 +47,7 @@ module TestTextLayouterHelpers
|
|
45
47
|
if item
|
46
48
|
assert_same(item.style, obj.item.style)
|
47
49
|
assert_equal(item.items, obj.item.items)
|
50
|
+
assert_equal(item.properties, obj.item.properties)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
@@ -83,12 +86,10 @@ describe HexaPDF::Layout::TextLayouter::SimpleTextSegmentation do
|
|
83
86
|
@obj = HexaPDF::Layout::TextLayouter::SimpleTextSegmentation
|
84
87
|
end
|
85
88
|
|
86
|
-
def setup_fragment(text, style =
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
HexaPDF::Layout::TextFragment.create(text, font: @font)
|
91
|
-
end
|
89
|
+
def setup_fragment(text, style = {font: @font})
|
90
|
+
fragment = HexaPDF::Layout::TextFragment.create(text, style)
|
91
|
+
fragment.properties['key'] = :value
|
92
|
+
fragment
|
92
93
|
end
|
93
94
|
|
94
95
|
it "handles InlineBox objects" do
|
@@ -138,11 +139,13 @@ describe HexaPDF::Layout::TextLayouter::SimpleTextSegmentation do
|
|
138
139
|
assert_equal([], result[index].item.items)
|
139
140
|
assert(result[index].item.items.frozen?)
|
140
141
|
assert_same(frag.style, result[index].item.style)
|
142
|
+
assert_equal(frag.properties, result[index].item.properties)
|
141
143
|
end
|
142
144
|
assert_penalty(result[15], HexaPDF::Layout::TextLayouter::Penalty::LINE_BREAK)
|
143
145
|
assert_equal([], result[15].item.items)
|
144
146
|
assert(result[15].item.items.frozen?)
|
145
147
|
assert_same(frag.style, result[15].item.style)
|
148
|
+
assert_equal(frag.properties, result[15].item.properties)
|
146
149
|
end
|
147
150
|
|
148
151
|
it "insert a standard penalty after a hyphen" do
|
@@ -86,24 +86,15 @@ describe HexaPDF::Composer do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
describe "style" do
|
89
|
-
it "
|
90
|
-
@composer.style(:base, font_size: 20)
|
91
|
-
assert_equal(20, @composer.style(:
|
92
|
-
|
93
|
-
assert_equal(
|
94
|
-
assert(@composer.style(:yet_another_new, base: :newstyle).subscript)
|
95
|
-
end
|
96
|
-
|
97
|
-
it "returns the named style" do
|
98
|
-
assert_kind_of(HexaPDF::Layout::Style, @composer.style(:base))
|
99
|
-
end
|
100
|
-
|
101
|
-
it "updates the style with the given properties" do
|
102
|
-
assert_equal(20, @composer.style(:base, font_size: 20).font_size)
|
89
|
+
it "delegates to layout.style" do
|
90
|
+
@composer.document.layout.style(:base, font_size: 20)
|
91
|
+
assert_equal(20, @composer.style(:base).font_size)
|
92
|
+
@composer.style(:base, font_size: 30)
|
93
|
+
assert_equal(30, @composer.document.layout.style(:base).font_size)
|
103
94
|
end
|
104
95
|
end
|
105
96
|
|
106
|
-
describe "text" do
|
97
|
+
describe "text/formatted_text/image/box" do
|
107
98
|
before do
|
108
99
|
test_self = self
|
109
100
|
@composer.define_singleton_method(:draw_box) do |arg|
|
@@ -111,151 +102,36 @@ describe HexaPDF::Composer do
|
|
111
102
|
end
|
112
103
|
end
|
113
104
|
|
114
|
-
it "
|
115
|
-
@composer.text("Test", width: 10, height: 15
|
105
|
+
it "delegates #text to layout.text" do
|
106
|
+
@composer.text("Test", width: 10, height: 15, style: {font_size: 20},
|
107
|
+
box_style: {font_size: 30}, line_spacing: 2)
|
116
108
|
assert_equal(10, @box.width)
|
117
109
|
assert_equal(15, @box.height)
|
118
|
-
|
110
|
+
assert_equal(30, @box.style.font_size)
|
119
111
|
items = @box.instance_variable_get(:@items)
|
120
112
|
assert_equal(1, items.length)
|
121
|
-
assert_same(
|
113
|
+
assert_same(20, items.first.style.font_size)
|
122
114
|
end
|
123
115
|
|
124
|
-
it "
|
125
|
-
style = HexaPDF::Layout::Style.new(font_size: 20, font: ['Times', {variant: :bold}])
|
126
|
-
@composer.text("Test", style: style)
|
127
|
-
assert_same(@box.style, style)
|
128
|
-
assert_same(@composer.document.fonts.add("Times", variant: :bold), @box.style.font)
|
129
|
-
assert_equal(20, @box.style.font_size)
|
130
|
-
|
131
|
-
@composer.text("Test", style: {font_size: 20})
|
132
|
-
assert_equal(20, @box.style.font_size)
|
133
|
-
|
134
|
-
@composer.style(:named, font_size: 20)
|
135
|
-
@composer.text("Test", style: :named)
|
136
|
-
assert_equal(20, @box.style.font_size)
|
137
|
-
end
|
138
|
-
|
139
|
-
it "updates the used style with the provided options" do
|
140
|
-
@composer.text("Test", style: {subscript: true}, font_size: 20)
|
141
|
-
assert_equal(20, @box.style.font_size)
|
142
|
-
end
|
143
|
-
|
144
|
-
it "allows using a box style different from the text style" do
|
145
|
-
style = HexaPDF::Layout::Style.new(font_size: 20)
|
146
|
-
@composer.text("Test", box_style: style)
|
147
|
-
refute_same(@box.instance_variable_get(:@items).first.style, style)
|
148
|
-
assert_same(@box.style, style)
|
149
|
-
|
150
|
-
@composer.style(:named, font_size: 20)
|
151
|
-
@composer.text("Test", box_style: :named)
|
152
|
-
assert_equal(20, @box.style.font_size)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
describe "formatted_text" do
|
157
|
-
before do
|
158
|
-
test_self = self
|
159
|
-
@composer.define_singleton_method(:draw_box) do |arg|
|
160
|
-
test_self.instance_variable_set(:@box, arg)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
it "creates a text box with the given text and draws it on the canvas" do
|
116
|
+
it "delegates #formatted_text to layout.formatted_text" do
|
165
117
|
@composer.formatted_text(["Test"], width: 10, height: 15)
|
166
118
|
assert_equal(10, @box.width)
|
167
119
|
assert_equal(15, @box.height)
|
168
120
|
assert_equal(1, @box.instance_variable_get(:@items).length)
|
169
121
|
end
|
170
122
|
|
171
|
-
it "
|
172
|
-
@composer.formatted_text([{text: "Test"}])
|
173
|
-
items = @box.instance_variable_get(:@items)
|
174
|
-
assert_equal(4, items[0].items.length)
|
175
|
-
end
|
176
|
-
|
177
|
-
it "uses an empty string if the :text key for a hash is not specified" do
|
178
|
-
@composer.formatted_text([{font_size: "Test"}])
|
179
|
-
items = @box.instance_variable_get(:@items)
|
180
|
-
assert_equal(0, items[0].items.length)
|
181
|
-
end
|
182
|
-
|
183
|
-
it "allows setting a custom base style for all parts" do
|
184
|
-
@composer.formatted_text(["Test", "other"], font_size: 20)
|
185
|
-
items = @box.instance_variable_get(:@items)
|
186
|
-
assert_equal(20, @box.style.font_size)
|
187
|
-
assert_equal(20, items[0].style.font_size)
|
188
|
-
assert_equal(20, items[1].style.font_size)
|
189
|
-
end
|
190
|
-
|
191
|
-
it "allows using custom style properties for a single part" do
|
192
|
-
@composer.formatted_text([{text: "Test", font_size: 20}, "test"], align: :center)
|
193
|
-
items = @box.instance_variable_get(:@items)
|
194
|
-
assert_equal(10, @box.style.font_size)
|
195
|
-
|
196
|
-
assert_equal(20, items[0].style.font_size)
|
197
|
-
assert_equal(:center, items[0].style.align)
|
198
|
-
|
199
|
-
assert_equal(10, items[1].style.font_size)
|
200
|
-
assert_equal(:center, items[1].style.align)
|
201
|
-
end
|
202
|
-
|
203
|
-
it "allows using a custom style as basis for a single part" do
|
204
|
-
@composer.formatted_text([{text: "Test", style: {font_size: 20}, subscript: true}, "test"],
|
205
|
-
align: :center)
|
206
|
-
items = @box.instance_variable_get(:@items)
|
207
|
-
assert_equal(10, @box.style.font_size)
|
208
|
-
|
209
|
-
assert_equal(20, items[0].style.font_size)
|
210
|
-
assert_equal(:left, items[0].style.align)
|
211
|
-
assert(items[0].style.subscript)
|
212
|
-
|
213
|
-
assert_equal(10, items[1].style.font_size)
|
214
|
-
assert_equal(:center, items[1].style.align)
|
215
|
-
refute(items[1].style.subscript)
|
216
|
-
end
|
217
|
-
|
218
|
-
it "allows specifying a link to an URL via the :link key" do
|
219
|
-
@composer.formatted_text([{text: "Test", link: "URI"}, {link: "URI"}, "test"])
|
220
|
-
items = @box.instance_variable_get(:@items)
|
221
|
-
assert_equal(3, items.length)
|
222
|
-
assert_equal(4, items[0].items.length, "text should be Test")
|
223
|
-
assert_equal(3, items[1].items.length, "text should be URI")
|
224
|
-
assert_equal([:link, {uri: 'URI'}], items[0].style.overlays.instance_variable_get(:@layers)[0])
|
225
|
-
refute(items[2].style.overlays?)
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
describe "image" do
|
230
|
-
it "creates an image box and draws it on the canvas" do
|
231
|
-
box = nil
|
232
|
-
@composer.define_singleton_method(:draw_box) {|arg| box = arg }
|
233
|
-
image_path = File.join(TEST_DATA_DIR, 'images', 'gray.jpg')
|
234
|
-
|
235
|
-
@composer.image(image_path, width: 10, height: 15, style: {font_size: 20}, subscript: true)
|
236
|
-
assert_equal(10, box.width)
|
237
|
-
assert_equal(15, box.height)
|
238
|
-
assert_equal(20, box.style.font_size)
|
239
|
-
assert(box.style.subscript)
|
240
|
-
assert_same(@composer.document.images.add(image_path), box.image)
|
241
|
-
end
|
242
|
-
|
243
|
-
it "allows using a form XObject" do
|
123
|
+
it "delegates #image to layout.image" do
|
244
124
|
form = @composer.document.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 10, 10]})
|
245
125
|
@composer.image(form, width: 10)
|
246
|
-
assert_equal(
|
247
|
-
assert_equal(
|
126
|
+
assert_equal(10, @box.width)
|
127
|
+
assert_equal(0, @box.height)
|
248
128
|
end
|
249
|
-
end
|
250
129
|
|
251
|
-
|
252
|
-
it "creates the named box and draws it on the canvas" do
|
253
|
-
box = nil
|
254
|
-
@composer.define_singleton_method(:draw_box) {|arg| box = arg }
|
130
|
+
it "delegates #box to layout.box" do
|
255
131
|
image = @composer.document.images.add(File.join(TEST_DATA_DIR, 'images', 'gray.jpg'))
|
256
132
|
@composer.box(:list, width: 20) {|list| list.image(image) }
|
257
|
-
assert_equal(20, box.width)
|
258
|
-
assert_same(image, box.children[0].image)
|
133
|
+
assert_equal(20, @box.width)
|
134
|
+
assert_same(image, @box.children[0].image)
|
259
135
|
end
|
260
136
|
end
|
261
137
|
|
@@ -25,10 +25,13 @@ describe HexaPDF::Revision do
|
|
25
25
|
HexaPDF::Object.new(nil, oid: entry.oid, gen: entry.gen)
|
26
26
|
else
|
27
27
|
case entry.oid
|
28
|
+
when 2 then HexaPDF::Dictionary.new({Type: :Sig}, oid: entry.oid, gen: entry.gen)
|
28
29
|
when 4 then HexaPDF::Dictionary.new({Type: :XRef}, oid: entry.oid, gen: entry.gen)
|
29
30
|
when 5 then HexaPDF::Dictionary.new({Type: :ObjStm}, oid: entry.oid, gen: entry.gen)
|
30
31
|
when 7 then HexaPDF::Type::Catalog.new({Type: :Catalog}, oid: entry.oid, gen: entry.gen,
|
31
32
|
document: self)
|
33
|
+
when 6 then HexaPDF::Dictionary.new({Array: HexaPDF::PDFArray.new([1, 2])},
|
34
|
+
oid: entry.oid, gen: entry.gen)
|
32
35
|
else HexaPDF::Object.new(:Test, oid: entry.oid, gen: entry.gen)
|
33
36
|
end
|
34
37
|
end
|
@@ -43,7 +46,7 @@ describe HexaPDF::Revision do
|
|
43
46
|
|
44
47
|
it "takes an xref section and/or a parser on initialization" do
|
45
48
|
rev = HexaPDF::Revision.new({}, loader: @loader, xref_section: @xref_section)
|
46
|
-
assert_equal(:
|
49
|
+
assert_equal({Type: :Sig}, rev.object(2).value)
|
47
50
|
end
|
48
51
|
|
49
52
|
it "returns the next free object number" do
|
@@ -100,7 +103,7 @@ describe HexaPDF::Revision do
|
|
100
103
|
|
101
104
|
it "loads an object that is defined in the cross-reference section" do
|
102
105
|
obj = @rev.object(HexaPDF::Reference.new(2, 0))
|
103
|
-
assert_equal(:
|
106
|
+
assert_equal({Type: :Sig}, obj.value)
|
104
107
|
assert_equal(2, obj.oid)
|
105
108
|
assert_equal(0, obj.gen)
|
106
109
|
end
|
@@ -190,7 +193,7 @@ describe HexaPDF::Revision do
|
|
190
193
|
|
191
194
|
describe "each_modified_object" do
|
192
195
|
it "returns modified objects" do
|
193
|
-
obj = @rev.object(
|
196
|
+
obj = @rev.object(3)
|
194
197
|
obj.value = :Other
|
195
198
|
@rev.add(@obj)
|
196
199
|
deleted = @rev.object(6)
|
@@ -214,6 +217,18 @@ describe HexaPDF::Revision do
|
|
214
217
|
obj.delete(:Type)
|
215
218
|
assert_equal([], @rev.each_modified_object.to_a)
|
216
219
|
end
|
220
|
+
|
221
|
+
it "doesn't return dictionaries that have direct HexaPDF::Object child objects" do
|
222
|
+
obj = @rev.object(6)
|
223
|
+
obj[:Array] = HexaPDF::PDFArray.new([1, 2]) # same value but differen #data instance
|
224
|
+
assert_equal([], @rev.each_modified_object.to_a)
|
225
|
+
end
|
226
|
+
|
227
|
+
it "doesn't return signature objects" do
|
228
|
+
obj = @rev.object(2)
|
229
|
+
obj[:x] = :y
|
230
|
+
assert_equal([], @rev.each_modified_object.to_a)
|
231
|
+
end
|
217
232
|
end
|
218
233
|
|
219
234
|
describe "reset_objects" do
|
data/test/hexapdf/test_writer.rb
CHANGED
@@ -40,7 +40,7 @@ describe HexaPDF::Writer do
|
|
40
40
|
219
|
41
41
|
%%EOF
|
42
42
|
3 0 obj
|
43
|
-
<</Producer(HexaPDF version 0.26.
|
43
|
+
<</Producer(HexaPDF version 0.26.2)>>
|
44
44
|
endobj
|
45
45
|
xref
|
46
46
|
3 1
|
@@ -72,7 +72,7 @@ describe HexaPDF::Writer do
|
|
72
72
|
141
|
73
73
|
%%EOF
|
74
74
|
6 0 obj
|
75
|
-
<</Producer(HexaPDF version 0.26.
|
75
|
+
<</Producer(HexaPDF version 0.26.2)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
@@ -206,7 +206,7 @@ describe HexaPDF::Writer do
|
|
206
206
|
<</Type/Page/MediaBox[0 0 595 842]/Parent 2 0 R/Resources<<>>>>
|
207
207
|
endobj
|
208
208
|
5 0 obj
|
209
|
-
<</Producer(HexaPDF version 0.26.
|
209
|
+
<</Producer(HexaPDF version 0.26.2)>>
|
210
210
|
endobj
|
211
211
|
4 0 obj
|
212
212
|
<</Root 1 0 R/Info 5 0 R/Size 6/Type/XRef/W[1 1 2]/Index[0 6]/Filter/FlateDecode/DecodeParms<</Columns 4/Predictor 12>>/Length 33>>stream
|
@@ -30,6 +30,12 @@ describe HexaPDF::Type::ObjectStream do
|
|
30
30
|
stream: "1 0 5 2 5 [1 2]")
|
31
31
|
end
|
32
32
|
|
33
|
+
it "parses an associated stream the first time the stored objects are accessed" do
|
34
|
+
assert_nil(@obj.instance_variable_get(:@objects))
|
35
|
+
assert_equal(0, @obj.object_index(HexaPDF::Reference.new(1, 0)))
|
36
|
+
assert_equal(1, @obj.object_index(HexaPDF::Reference.new(5, 0)))
|
37
|
+
end
|
38
|
+
|
33
39
|
it "correctly parses stream data" do
|
34
40
|
data = @obj.parse_stream
|
35
41
|
assert_equal([5, 1], data.object_by_index(0))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hexapdf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.26.
|
4
|
+
version: 0.26.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Leitner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|
@@ -706,7 +706,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
706
706
|
- !ruby/object:Gem::Version
|
707
707
|
version: '0'
|
708
708
|
requirements: []
|
709
|
-
rubygems_version: 3.
|
709
|
+
rubygems_version: 3.2.32
|
710
710
|
signing_key:
|
711
711
|
specification_version: 4
|
712
712
|
summary: HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|