hexapdf 0.9.1 → 0.9.2
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 +7 -0
- data/CONTRIBUTERS +1 -1
- data/VERSION +1 -1
- data/lib/hexapdf/encryption/aes.rb +8 -3
- data/lib/hexapdf/filter/flate_decode.rb +5 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/encryption/test_aes.rb +12 -10
- data/test/hexapdf/filter/test_flate_decode.rb +11 -2
- data/test/hexapdf/test_writer.rb +2 -2
- metadata +2 -4
- data/examples/019-column_box.rb +0 -57
- data/lib/hexapdf/layout/column_box.rb +0 -161
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee462224ffa152978df2a0aebd05b52c7a75a21655880858bbb4b61e2eccd3dd
|
4
|
+
data.tar.gz: dc2eedf3a556c7a85fbfb229372512043f33200c6ffb6223b344c96bf4aff91b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da87ec95143ad653a606c699dc4e29ac3e4abf6b4e1a0bfc535ede8221f047ab35f7b69556eaa7b7cf23d7da69909685c515d98ea67f1e1e0265ebbb460f2eb7
|
7
|
+
data.tar.gz: f47ec5e10af27baf8a8ee06d4f496f53841b57acc93ce1111288576a473dfb73d73052aa65f21835e19ebadb6e87868fcc3d63f84c82dbfd81dca7ae56eb9975
|
data/CHANGELOG.md
CHANGED
data/CONTRIBUTERS
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.2
|
@@ -170,13 +170,18 @@ module HexaPDF
|
|
170
170
|
# Removes the padding from the data according to the PKCS#5 padding scheme and returns the
|
171
171
|
# result.
|
172
172
|
#
|
173
|
+
# In case the padding is not correct as per the specification, it is assumed that there is
|
174
|
+
# no padding and the input is returned as is.
|
175
|
+
#
|
173
176
|
# See: PDF1.7 s7.6.2
|
174
177
|
def unpad(data)
|
175
178
|
padding_length = data.getbyte(-1)
|
176
|
-
if padding_length > BLOCK_SIZE || padding_length == 0
|
177
|
-
|
179
|
+
if padding_length > BLOCK_SIZE || padding_length == 0 ||
|
180
|
+
data[-padding_length, padding_length].each_byte.any? {|byte| byte != padding_length }
|
181
|
+
data
|
182
|
+
else
|
183
|
+
data[0...-padding_length]
|
178
184
|
end
|
179
|
-
data[0...-padding_length]
|
180
185
|
end
|
181
186
|
|
182
187
|
end
|
@@ -49,10 +49,14 @@ module HexaPDF
|
|
49
49
|
module FlateDecode
|
50
50
|
|
51
51
|
# See HexaPDF::Filter
|
52
|
+
#
|
53
|
+
# The decoder also handles the case of an empty string not deflated to a correct flate stream
|
54
|
+
# but just output as an empty string.
|
52
55
|
def self.decoder(source, options = nil)
|
53
56
|
fib = Fiber.new do
|
54
57
|
inflater = Zlib::Inflate.new
|
55
58
|
while source.alive? && (data = source.resume)
|
59
|
+
next if data.empty?
|
56
60
|
begin
|
57
61
|
data = inflater.inflate(data)
|
58
62
|
rescue StandardError => e
|
@@ -61,7 +65,7 @@ module HexaPDF
|
|
61
65
|
Fiber.yield(data)
|
62
66
|
end
|
63
67
|
begin
|
64
|
-
data = (data = inflater.finish).empty? ? nil : data
|
68
|
+
data = inflater.total_in == 0 || (data = inflater.finish).empty? ? nil : data
|
65
69
|
inflater.close
|
66
70
|
data
|
67
71
|
rescue StandardError => e
|
data/lib/hexapdf/version.rb
CHANGED
@@ -48,12 +48,6 @@ describe HexaPDF::Encryption::AES do
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
it "fails on decryption if the padding is invalid" do
|
52
|
-
assert_raises(HexaPDF::EncryptionError) do
|
53
|
-
@algorithm_class.decrypt('some' * 4, 'iv' * 8 + 'somedata' * 4)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
51
|
it "fails on decryption if not enough bytes are provided" do
|
58
52
|
assert_raises(HexaPDF::EncryptionError) do
|
59
53
|
@algorithm_class.decrypt('some' * 4, 'no iv')
|
@@ -102,10 +96,18 @@ describe HexaPDF::Encryption::AES do
|
|
102
96
|
assert_equal('a' * 40, result)
|
103
97
|
end
|
104
98
|
|
105
|
-
it "
|
106
|
-
|
107
|
-
|
108
|
-
|
99
|
+
it "decryption works if the padding is invalid" do
|
100
|
+
f = Fiber.new { 'a' * 32 }
|
101
|
+
result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
|
102
|
+
assert_equal('a' * 16, result)
|
103
|
+
|
104
|
+
f = Fiber.new { 'a' * 31 + "\x00" }
|
105
|
+
result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
|
106
|
+
assert_equal('a' * 15 + "\x00", result)
|
107
|
+
|
108
|
+
f = Fiber.new { 'a' * 29 + "\x00\x01\x03" }
|
109
|
+
result = TestHelper.collector(@algorithm_class.decryption_fiber('some' * 4, f))
|
110
|
+
assert_equal('a' * 13 + "\x00\x01\x03", result)
|
109
111
|
end
|
110
112
|
|
111
113
|
it "fails on decryption if not enough bytes are provided" do
|
@@ -17,13 +17,22 @@ describe HexaPDF::Filter::FlateDecode do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
describe "decoder" do
|
20
|
+
it "works for empty input" do
|
21
|
+
assert_equal('', collector(@obj.decoder(Fiber.new { "" })))
|
22
|
+
assert_equal('', collector(@obj.decoder(Fiber.new {})))
|
23
|
+
end
|
24
|
+
|
20
25
|
it "applies the Predictor after decoding" do
|
21
26
|
assert_equal(@decoded, collector(@obj.decoder(feeder(@encoded_predictor), @predictor_opts)))
|
22
27
|
end
|
23
28
|
|
24
29
|
it "fails on invalid input" do
|
25
|
-
assert_raises(HexaPDF::FilterError)
|
26
|
-
|
30
|
+
assert_raises(HexaPDF::FilterError) do
|
31
|
+
collector(@obj.decoder(feeder(@encoded[0..-2], @encoded.length - 3)))
|
32
|
+
end
|
33
|
+
assert_raises(HexaPDF::FilterError) do
|
34
|
+
collector(@obj.decoder(feeder("some data")))
|
35
|
+
end
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
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.9.
|
43
|
+
<</Producer(HexaPDF version 0.9.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.9.
|
75
|
+
<</Producer(HexaPDF version 0.9.2)>>
|
76
76
|
endobj
|
77
77
|
2 0 obj
|
78
78
|
<</Length 10>>stream
|
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.9.
|
4
|
+
version: 0.9.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: 2019-
|
11
|
+
date: 2019-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cmdparse
|
@@ -206,7 +206,6 @@ files:
|
|
206
206
|
- examples/016-frame_automatic_box_placement.rb
|
207
207
|
- examples/017-frame_text_flow.rb
|
208
208
|
- examples/018-composer.rb
|
209
|
-
- examples/019-column_box.rb
|
210
209
|
- examples/emoji-smile.png
|
211
210
|
- examples/emoji-wink.png
|
212
211
|
- examples/machupicchu.jpg
|
@@ -318,7 +317,6 @@ files:
|
|
318
317
|
- lib/hexapdf/importer.rb
|
319
318
|
- lib/hexapdf/layout.rb
|
320
319
|
- lib/hexapdf/layout/box.rb
|
321
|
-
- lib/hexapdf/layout/column_box.rb
|
322
320
|
- lib/hexapdf/layout/frame.rb
|
323
321
|
- lib/hexapdf/layout/image_box.rb
|
324
322
|
- lib/hexapdf/layout/inline_box.rb
|
data/examples/019-column_box.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
# ## Column Box
|
2
|
-
#
|
3
|
-
# This example shows how [HexaPDF::Layout::Frame] and [HexaPDF::Layout::TextBox]
|
4
|
-
# can be used to flow text around objects.
|
5
|
-
#
|
6
|
-
# Three boxes are placed repeatedly onto the frame until it is filled: two
|
7
|
-
# floating boxes (one left, one right) and a text box. The text box is styled to
|
8
|
-
# flow its content around the other two boxes.
|
9
|
-
#
|
10
|
-
# Usage:
|
11
|
-
# : `ruby frame_text_flow.rb`
|
12
|
-
#
|
13
|
-
|
14
|
-
require 'hexapdf'
|
15
|
-
require 'hexapdf/utils/graphics_helpers'
|
16
|
-
|
17
|
-
include HexaPDF::Layout
|
18
|
-
include HexaPDF::Utils::GraphicsHelpers
|
19
|
-
|
20
|
-
doc = HexaPDF::Document.new
|
21
|
-
|
22
|
-
sample_text = "Lorem ipsum dolor sit amet, con\u{00AD}sectetur
|
23
|
-
adipis\u{00AD}cing elit, sed do eiusmod tempor incididunt ut labore et
|
24
|
-
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
|
25
|
-
ullamco laboris nisi ut aliquip ex ea commodo consequat.
|
26
|
-
".tr("\n", ' ') * 5
|
27
|
-
items = [TextFragment.create(sample_text, font: doc.fonts.add("Times"))]
|
28
|
-
|
29
|
-
page = doc.pages.add
|
30
|
-
media_box = page.box(:media)
|
31
|
-
canvas = page.canvas
|
32
|
-
frame = Frame.new(media_box.left + 20, media_box.bottom + 20,
|
33
|
-
media_box.width - 40, media_box.height - 40)
|
34
|
-
|
35
|
-
image = doc.images.add(File.join(__dir__, 'machupicchu.jpg'))
|
36
|
-
iw, ih = calculate_dimensions(image.width, image.height, rwidth: 100)
|
37
|
-
|
38
|
-
boxes = []
|
39
|
-
3.times do
|
40
|
-
boxes << Box.create(width: iw, height: ih,
|
41
|
-
margin: [10, 30], position: :float) do |canv, box|
|
42
|
-
canv.image(image, at: [0, 0], width: 100)
|
43
|
-
end
|
44
|
-
boxes << Box.create(width: 50, height: 50, margin: 20,
|
45
|
-
position: :float, position_hint: :right,
|
46
|
-
border: {width: 1, color: [[255, 0, 0]]})
|
47
|
-
boxes << TextBox.new(items, style: {position: :flow, align: :justify})
|
48
|
-
end
|
49
|
-
columns = ColumnBox.new(boxes) #, style: {position: :flow})
|
50
|
-
polygon = Geom2D::Polygon([250, 350], [350, 350], [350, 500], [250, 500])
|
51
|
-
#frame.remove_area(polygon)
|
52
|
-
#canvas.draw(:geom2d, object: polygon)
|
53
|
-
result = frame.fit(columns)
|
54
|
-
p result.success?
|
55
|
-
frame.draw(canvas, result)
|
56
|
-
|
57
|
-
doc.write("column_box.pdf", optimize: true)
|
@@ -1,161 +0,0 @@
|
|
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
|
-
require 'hexapdf/layout/box'
|
37
|
-
|
38
|
-
module HexaPDF
|
39
|
-
module Layout
|
40
|
-
|
41
|
-
# A ColumnBox arranges boxes in one or more columns.
|
42
|
-
#
|
43
|
-
# The number of columns as well as the size of the gap between the columns can be modified.
|
44
|
-
class ColumnBox < Box
|
45
|
-
|
46
|
-
# The child boxes of this ColumnBox.
|
47
|
-
attr_reader :children
|
48
|
-
|
49
|
-
# The number of columns.
|
50
|
-
# TODO: allow array with column widths later like [100, :*, :*]; same for gaps
|
51
|
-
attr_reader :columns
|
52
|
-
|
53
|
-
# The size of the gap between the columns.
|
54
|
-
attr_reader :gap
|
55
|
-
|
56
|
-
# Creates a new ColumnBox object for the given +children+ boxes.
|
57
|
-
def initialize(children = [], columns = 2, gap: 36, **kwargs)
|
58
|
-
super(kwargs, &:unused_draw_block)
|
59
|
-
@children = children
|
60
|
-
@columns = columns
|
61
|
-
@gap = gap
|
62
|
-
end
|
63
|
-
|
64
|
-
# Fits the column box into the available space.
|
65
|
-
def fit(available_width, available_height, frame)
|
66
|
-
last_height_difference = 1_000_000
|
67
|
-
height = if style.position == :flow
|
68
|
-
frame.height
|
69
|
-
else
|
70
|
-
(@initial_height > 0 ? @initial_height : available_height) - reserved_height
|
71
|
-
end
|
72
|
-
while true
|
73
|
-
@frames = []
|
74
|
-
if style.position == :flow
|
75
|
-
column_width = (frame.width - gap * (@columns - 1)).to_f / @columns
|
76
|
-
@columns.times do |col_nr|
|
77
|
-
left = (column_width + gap) * col_nr + frame.left
|
78
|
-
bottom = frame.bottom
|
79
|
-
rect = Geom2D::Polygon([left, bottom],
|
80
|
-
[left + column_width, bottom],
|
81
|
-
[left + column_width, bottom + height],
|
82
|
-
[left, bottom + height])
|
83
|
-
shape = Geom2D::Algorithms::PolygonOperation.run(frame.shape, rect, :intersection)
|
84
|
-
col_frame = Frame.new(left, bottom, column_width, height)
|
85
|
-
col_frame.shape = shape
|
86
|
-
@frames << col_frame
|
87
|
-
end
|
88
|
-
@frame_index = 0
|
89
|
-
@results = @children.map {|child_box| fit_box(child_box) }
|
90
|
-
@width = frame.width
|
91
|
-
@height = frame.height - @frames.min_by(&:y).y
|
92
|
-
else
|
93
|
-
width = (@initial_width > 0 ? @initial_width : available_width) - reserved_width
|
94
|
-
column_width = (width - gap * (@columns - 1)).to_f / @columns
|
95
|
-
@columns.times do |col_nr|
|
96
|
-
@frames << Frame.new((column_width + gap) * col_nr, 0, column_width, height)
|
97
|
-
end
|
98
|
-
@frame_index = 0
|
99
|
-
@results = @children.map {|child_box| fit_box(child_box) }
|
100
|
-
@width = width
|
101
|
-
@height = height - @frames.min_by(&:y).y
|
102
|
-
end
|
103
|
-
min_y, max_y = @frames.minmax_by(&:y).map(&:y)
|
104
|
-
p [height, @frames.map(&:y), last_height_difference, min_y, max_y]
|
105
|
-
# TOOD: @result.any?(&:empty?) only for the first run!!!! if the first run fails, we
|
106
|
-
# cannot balance the columns because there is too much content.
|
107
|
-
# TODO: another break condition is if the @results didn't change since the last run
|
108
|
-
break if max_y != height && (@results.any?(&:empty?) ||
|
109
|
-
max_y - min_y >= last_height_difference ||
|
110
|
-
max_y - min_y < 0.5)
|
111
|
-
last_height_difference = max_y - min_y
|
112
|
-
height -= last_height_difference / 2.0
|
113
|
-
p [height]
|
114
|
-
end
|
115
|
-
@results.all? {|res| res.length == 1 }
|
116
|
-
end
|
117
|
-
|
118
|
-
private
|
119
|
-
|
120
|
-
def fit_box(box)
|
121
|
-
cur_frame = @frames[@frame_index]
|
122
|
-
fitted_boxes = []
|
123
|
-
while true && cur_frame
|
124
|
-
result = cur_frame.fit(box)
|
125
|
-
if result.success?
|
126
|
-
cur_frame.remove_area(result.mask)
|
127
|
-
fitted_boxes << result
|
128
|
-
break
|
129
|
-
elsif cur_frame.full?
|
130
|
-
@frame_index += 1
|
131
|
-
break if @frame_index == @frames.length
|
132
|
-
cur_frame = @frames[@frame_index]
|
133
|
-
else
|
134
|
-
draw_box, box = cur_frame.split(result)
|
135
|
-
if draw_box
|
136
|
-
cur_frame.remove_area(result.mask)
|
137
|
-
fitted_boxes << result
|
138
|
-
elsif !cur_frame.find_next_region
|
139
|
-
@frame_index += 1
|
140
|
-
break if @frame_index == @frames.length
|
141
|
-
cur_frame = @frames[@frame_index]
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
fitted_boxes
|
146
|
-
end
|
147
|
-
|
148
|
-
# Draws the child boxes onto the canvas at position [x, y].
|
149
|
-
def draw_content(canvas, x, y)
|
150
|
-
x = y = 0 if style.position == :flow
|
151
|
-
@results.each do |result_boxes|
|
152
|
-
result_boxes.each do |result|
|
153
|
-
result.box.draw(canvas, x + result.x, y + result.y)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
159
|
-
|
160
|
-
end
|
161
|
-
end
|