hexapdf 0.18.0 → 0.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -2
- data/lib/hexapdf/cli/command.rb +7 -1
- data/lib/hexapdf/content/canvas.rb +2 -2
- data/lib/hexapdf/content/graphics_state.rb +144 -21
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +46 -3
- data/lib/hexapdf/version.rb +1 -1
- data/test/data/cert/create.sh +171 -0
- data/test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF39.pem +119 -0
- data/test/data/cert/root-ca/certs/84E66B6F4C359E741C0AFA014790DF3A.pem +125 -0
- data/test/data/cert/root-ca/db/crlnumber +1 -0
- data/test/data/cert/root-ca/db/index +2 -0
- data/test/data/cert/root-ca/db/index.attr +1 -0
- data/test/data/cert/root-ca/db/index.attr.old +1 -0
- data/test/data/cert/root-ca/db/index.old +1 -0
- data/test/data/cert/root-ca/db/serial +1 -0
- data/test/data/cert/root-ca/db/serial.old +1 -0
- data/test/data/cert/root-ca/private/root-ca.key +52 -0
- data/test/data/cert/root-ca/root-ca.conf +65 -0
- data/test/data/cert/root-ca/root-ca.crt +119 -0
- data/test/data/cert/root-ca/root-ca.csr +28 -0
- data/test/data/cert/signature-1-pkcs7-detached.pdf +182 -0
- data/test/data/cert/sub-ca/certs/453FF080E3EDCD6A388D5368DFC320D9.pem +125 -0
- data/test/data/cert/sub-ca/db/crlnumber +1 -0
- data/test/data/cert/sub-ca/db/index +1 -0
- data/test/data/cert/sub-ca/db/index.attr +1 -0
- data/test/data/cert/sub-ca/db/index.old +0 -0
- data/test/data/cert/sub-ca/db/serial +1 -0
- data/test/data/cert/sub-ca/db/serial.old +1 -0
- data/test/data/cert/sub-ca/private/signing.key +52 -0
- data/test/data/cert/sub-ca/private/sub-ca.key +52 -0
- data/test/data/cert/sub-ca/signing.crt +125 -0
- data/test/data/cert/sub-ca/signing.csr +28 -0
- data/test/data/cert/sub-ca/signing.p12 +0 -0
- data/test/data/cert/sub-ca/sub-ca.conf +65 -0
- data/test/data/cert/sub-ca/sub-ca.crt +125 -0
- data/test/data/cert/sub-ca/sub-ca.csr +28 -0
- data/test/hexapdf/task/test_optimize.rb +26 -0
- data/test/hexapdf/test_dictionary_fields.rb +1 -0
- data/test/hexapdf/test_writer.rb +2 -2
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55ddbf5c737ab446c5793660957e64aaf6f8872c6bb1c4a76ba39a87193b951f
|
4
|
+
data.tar.gz: eb29fbb41cbb20c060c43cc80406bd4b11fa36b0d86a95daa9d1093d060ab89e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 28368cd415cd9adf28050df8812a0cda999b8140fcba4a9f307d7e37f6dc0254d99abf5173a81a1b2b59f9f6a658a46f6998d7834b93ffc19840d578e507ce92
|
7
|
+
data.tar.gz: b25e409653a4bd9359f3a39c2920187261a43151942c4120d2bd818886dbf236f77483a42ca7a7fb39ffbcdfc7da8cf9d7a87609a4f4af514cf7f93f495eb5ed
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 0.19.0 - 2021-11-24
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* Page resource pruning to the optimization task
|
6
|
+
* An option for page resources pruning to the optimization options of the
|
7
|
+
`hexapdf` command
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
|
11
|
+
* Handling of invalid date strings with a minute time zone offset greater than
|
12
|
+
59
|
13
|
+
|
14
|
+
|
1
15
|
## 0.18.0 - 2021-11-04
|
2
16
|
|
3
17
|
### Added
|
@@ -6,7 +20,7 @@
|
|
6
20
|
device colors in parts other than the canvas
|
7
21
|
* [HexaPDF::Type::AcroForm::VariableTextField::create_appearance_string] for
|
8
22
|
centralized creation of appearance strings
|
9
|
-
* [HexaPDF::Object
|
23
|
+
* [HexaPDF::Object::make_direct] for making objects and all parts of them direct
|
10
24
|
instead of indirect
|
11
25
|
|
12
26
|
### Changed
|
@@ -26,7 +40,7 @@
|
|
26
40
|
dictionary are indirect objects
|
27
41
|
* [HexaPDF::Content::GraphicObject::EndpointArc] to correctly determine the
|
28
42
|
start and end points
|
29
|
-
*
|
43
|
+
* HexaPDF::Dictionary#perform_validation to correctly handle objects that
|
30
44
|
should not be indirect objects
|
31
45
|
|
32
46
|
|
data/lib/hexapdf/cli/command.rb
CHANGED
@@ -66,6 +66,7 @@ module HexaPDF
|
|
66
66
|
@out_options.xref_streams = :preserve
|
67
67
|
@out_options.streams = :preserve
|
68
68
|
@out_options.optimize_fonts = false
|
69
|
+
@out_options.prune_page_resources = false
|
69
70
|
|
70
71
|
@out_options.encryption = :preserve
|
71
72
|
@out_options.enc_user_pwd = @out_options.enc_owner_pwd = nil
|
@@ -169,6 +170,10 @@ module HexaPDF
|
|
169
170
|
"time; default: #{@out_options.compress_pages})") do |c|
|
170
171
|
@out_options.compress_pages = c
|
171
172
|
end
|
173
|
+
options.on("--[no-]prune-page-resources", "Prunes unused objects from the page resources " \
|
174
|
+
"(may take a long time; default: #{@out_options.prune_page_resources})") do |c|
|
175
|
+
@out_options.prune_page_resources = c
|
176
|
+
end
|
172
177
|
options.on("--[no-]optimize-fonts", "Optimize embedded font files; " \
|
173
178
|
"default: #{@out_options.optimize_fonts})") do |o|
|
174
179
|
@out_options.optimize_fonts = o
|
@@ -236,7 +241,8 @@ module HexaPDF
|
|
236
241
|
doc.task(:optimize, compact: @out_options.compact,
|
237
242
|
object_streams: @out_options.object_streams,
|
238
243
|
xref_streams: @out_options.xref_streams,
|
239
|
-
compress_pages: @out_options.compress_pages
|
244
|
+
compress_pages: @out_options.compress_pages,
|
245
|
+
prune_page_resources: @out_options.prune_page_resources)
|
240
246
|
if @out_options.streams != :preserve || @out_options.optimize_fonts
|
241
247
|
doc.each(only_current: false) do |obj|
|
242
248
|
optimize_stream(obj)
|
@@ -589,7 +589,7 @@ module HexaPDF
|
|
589
589
|
#
|
590
590
|
# The line cap style specifies how the ends of stroked open paths should look like.
|
591
591
|
#
|
592
|
-
# The +style+ parameter can be one of:
|
592
|
+
# The +style+ parameter can be one of (also see LineCapStyle):
|
593
593
|
#
|
594
594
|
# :butt or 0::
|
595
595
|
# Stroke is squared off at the endpoint of a path.
|
@@ -641,7 +641,7 @@ module HexaPDF
|
|
641
641
|
#
|
642
642
|
# The line join style specifies the shape that is used at the corners of stroked paths.
|
643
643
|
#
|
644
|
-
# The +style+ parameter can be one of:
|
644
|
+
# The +style+ parameter can be one of (also see LineJoinStyle):
|
645
645
|
#
|
646
646
|
# :miter or 0::
|
647
647
|
# The outer lines of the two segments continue until the meet at an angle.
|
@@ -73,7 +73,7 @@ module HexaPDF
|
|
73
73
|
end
|
74
74
|
|
75
75
|
# Defines all available line cap styles as constants. Each line cap style is an instance of
|
76
|
-
# NamedValue. For use with Content::
|
76
|
+
# NamedValue, see ::normalize. For use with e.g. Content::Canvas#line_cap_style.
|
77
77
|
#
|
78
78
|
# See: PDF1.7 s8.4.3.3
|
79
79
|
module LineCapStyle
|
@@ -95,18 +95,39 @@ module HexaPDF
|
|
95
95
|
end
|
96
96
|
|
97
97
|
# Stroke is squared off at the endpoint of a path.
|
98
|
+
#
|
99
|
+
# Specify as 0 or :butt.
|
100
|
+
#
|
101
|
+
# #>pdf-small-hide
|
102
|
+
# canvas.line_cap_style(:butt)
|
103
|
+
# canvas.line_width(10).line(50, 20, 50, 80).stroke
|
104
|
+
# canvas.stroke_color("white").line_width(1).line(50, 20, 50, 80).stroke
|
98
105
|
BUTT_CAP = NamedValue.new(:butt, 0)
|
99
106
|
|
100
107
|
# A semicircular arc is drawn at the endpoint of a path.
|
108
|
+
#
|
109
|
+
# Specify as 1 or :round.
|
110
|
+
#
|
111
|
+
# #>pdf-small-hide
|
112
|
+
# canvas.line_cap_style(:round)
|
113
|
+
# canvas.line_width(10).line(50, 20, 50, 80).stroke
|
114
|
+
# canvas.stroke_color("white").line_width(1).line(50, 20, 50, 80).stroke
|
101
115
|
ROUND_CAP = NamedValue.new(:round, 1)
|
102
116
|
|
103
117
|
# The stroke continues half the line width beyond the endpoint of a path.
|
118
|
+
#
|
119
|
+
# Specify as 2 or :projecting_square.
|
120
|
+
#
|
121
|
+
# #>pdf-small-hide
|
122
|
+
# canvas.line_cap_style(:projecting_square)
|
123
|
+
# canvas.line_width(10).line(50, 20, 50, 80).stroke
|
124
|
+
# canvas.stroke_color("white").line_width(1).line(50, 20, 50, 80).stroke
|
104
125
|
PROJECTING_SQUARE_CAP = NamedValue.new(:projecting_square, 2)
|
105
126
|
|
106
127
|
end
|
107
128
|
|
108
129
|
# Defines all available line join styles as constants. Each line join style is an instance of
|
109
|
-
# NamedValue
|
130
|
+
# NamedValue, see ::normalize For use with e.g. Content::Canvas#line_join_style.
|
110
131
|
#
|
111
132
|
# See: PDF1.7 s8.4.3.4
|
112
133
|
module LineJoinStyle
|
@@ -127,20 +148,47 @@ module HexaPDF
|
|
127
148
|
end
|
128
149
|
end
|
129
150
|
|
130
|
-
# The outer lines of the two segments continue until
|
151
|
+
# The outer lines of the two segments continue until they meet at an angle.
|
152
|
+
#
|
153
|
+
# Specify as 0 or :miter.
|
154
|
+
#
|
155
|
+
# #>pdf-small-hide
|
156
|
+
# canvas.line_join_style(:miter)
|
157
|
+
# canvas.line_width(10).
|
158
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
159
|
+
# canvas.stroke_color("white").line_width(1).line_join_style(:bevel).
|
160
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
131
161
|
MITER_JOIN = NamedValue.new(:miter, 0)
|
132
162
|
|
133
163
|
# An arc of a circle is drawn around the point where the segments meet.
|
164
|
+
#
|
165
|
+
# Specify as 1 or :round.
|
166
|
+
#
|
167
|
+
# #>pdf-small-hide
|
168
|
+
# canvas.line_join_style(:round)
|
169
|
+
# canvas.line_width(10).
|
170
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
171
|
+
# canvas.stroke_color("white").line_width(1).line_join_style(:bevel).
|
172
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
134
173
|
ROUND_JOIN = NamedValue.new(:round, 1)
|
135
174
|
|
136
|
-
# The two segments are finished with butt caps and the space between the ends is filled with
|
137
|
-
#
|
175
|
+
# The two segments are finished with butt caps and the space between the ends is filled with a
|
176
|
+
# triangle.
|
177
|
+
#
|
178
|
+
# Specify as 2 or :bevel.
|
179
|
+
#
|
180
|
+
# #>pdf-small-hide
|
181
|
+
# canvas.line_join_style(:bevel)
|
182
|
+
# canvas.line_width(10).
|
183
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
184
|
+
# canvas.stroke_color("white").line_width(1).line_join_style(:bevel).
|
185
|
+
# polyline(20, 20, 50, 80, 80, 20).stroke
|
138
186
|
BEVEL_JOIN = NamedValue.new(:bevel, 2)
|
139
187
|
|
140
188
|
end
|
141
189
|
|
142
|
-
# The line dash pattern defines how a line should be dashed. For use with
|
143
|
-
# Content::
|
190
|
+
# The line dash pattern defines how a line should be dashed. For use with e.g.
|
191
|
+
# Content::Canvas#line_dash_pattern.
|
144
192
|
#
|
145
193
|
# A dash pattern consists of two parts: the dash array and the dash phase. The dash array
|
146
194
|
# defines the length of alternating dashes and gaps (important: starting with dashes). And the
|
@@ -159,6 +207,12 @@ module HexaPDF
|
|
159
207
|
# See: PDF1.7 s8.4.3.6
|
160
208
|
class LineDashPattern
|
161
209
|
|
210
|
+
# :call-seq:
|
211
|
+
# LineDashPattern.normalize(line_dash_pattern) -> line_dash_pattern
|
212
|
+
# LineDashPattern.normalize(array, phase = 0) -> LineDashPattern.new(array, phase)
|
213
|
+
# LineDashPattern.normalize(number, phase = 0) -> LineDashPattern.new([number], phase)
|
214
|
+
# LineDashPattern.normalize(0) -> LineDashPattern.new
|
215
|
+
#
|
162
216
|
# Returns the arguments normalized to a valid LineDashPattern instance.
|
163
217
|
#
|
164
218
|
# If +array+ is 0, the default line dash pattern representing a solid line will be used. If it
|
@@ -206,8 +260,8 @@ module HexaPDF
|
|
206
260
|
|
207
261
|
end
|
208
262
|
|
209
|
-
# Defines all available rendering intents as constants. For use with
|
210
|
-
# Content::
|
263
|
+
# Defines all available rendering intents as constants. For use with e.g.
|
264
|
+
# Content::Canvas#rendering_intent.
|
211
265
|
#
|
212
266
|
# See: PDF1.7 s8.6.5.8
|
213
267
|
module RenderingIntent
|
@@ -241,7 +295,7 @@ module HexaPDF
|
|
241
295
|
end
|
242
296
|
|
243
297
|
# Defines all available text rendering modes as constants. Each text rendering mode is an
|
244
|
-
# instance of NamedValue. For use with Content::
|
298
|
+
# instance of NamedValue. For use with e.g. Content::Canvas#text_rendering_mode.
|
245
299
|
#
|
246
300
|
# See: PDF1.7 s9.3.6
|
247
301
|
module TextRenderingMode
|
@@ -272,28 +326,97 @@ module HexaPDF
|
|
272
326
|
end
|
273
327
|
end
|
274
328
|
|
275
|
-
# Fill text
|
329
|
+
# Fill text.
|
330
|
+
#
|
331
|
+
# Specify as 0 or :fill.
|
332
|
+
#
|
333
|
+
# #>pdf-small-hide
|
334
|
+
# canvas.font("Helvetica", size: 13)
|
335
|
+
# canvas.stroke_color("green").line_width(0.5)
|
336
|
+
# canvas.text_rendering_mode(:fill)
|
337
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
276
338
|
FILL = NamedValue.new(:fill, 0)
|
277
339
|
|
278
|
-
# Stroke text
|
340
|
+
# Stroke text.
|
341
|
+
#
|
342
|
+
# Specify as 1 or :stroke.
|
343
|
+
#
|
344
|
+
# #>pdf-small-hide
|
345
|
+
# canvas.font("Helvetica", size: 13)
|
346
|
+
# canvas.stroke_color("green").line_width(0.5)
|
347
|
+
# canvas.text_rendering_mode(:stroke)
|
348
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
279
349
|
STROKE = NamedValue.new(:stroke, 1)
|
280
350
|
|
281
|
-
# Fill, then stroke text
|
351
|
+
# Fill, then stroke text.
|
352
|
+
#
|
353
|
+
# Specify as 2 or :fill_stroke.
|
354
|
+
#
|
355
|
+
# #>pdf-small-hide
|
356
|
+
# canvas.font("Helvetica", size: 13)
|
357
|
+
# canvas.stroke_color("green").line_width(0.5)
|
358
|
+
# canvas.text_rendering_mode(:fill_stroke)
|
359
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
282
360
|
FILL_STROKE = NamedValue.new(:fill_stroke, 2)
|
283
361
|
|
284
|
-
# Neither fill nor stroke text (invisible)
|
362
|
+
# Neither fill nor stroke text (invisible).
|
363
|
+
#
|
364
|
+
# Specify as 3 or :invisible.
|
365
|
+
#
|
366
|
+
# #>pdf-small-hide
|
367
|
+
# canvas.font("Helvetica", size: 13)
|
368
|
+
# canvas.stroke_color("green").line_width(0.5)
|
369
|
+
# canvas.text_rendering_mode(:invisible)
|
370
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
371
|
+
# canvas.stroke_color("red").line_width(20).line(30, 20, 30, 80).stroke
|
285
372
|
INVISIBLE = NamedValue.new(:invisible, 3)
|
286
373
|
|
287
|
-
# Fill text and add to path for clipping
|
374
|
+
# Fill text and add to path for clipping.
|
375
|
+
#
|
376
|
+
# Specify as 4 or :fill_clip.
|
377
|
+
#
|
378
|
+
# #>pdf-small-hide
|
379
|
+
# canvas.font("Helvetica", size: 13)
|
380
|
+
# canvas.stroke_color("green").line_width(0.5)
|
381
|
+
# canvas.text_rendering_mode(:fill_clip)
|
382
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
383
|
+
# canvas.stroke_color("red").line_width(20).line(30, 20, 30, 80).stroke
|
288
384
|
FILL_CLIP = NamedValue.new(:fill_clip, 4)
|
289
385
|
|
290
|
-
# Stroke text and add to path for clipping
|
386
|
+
# Stroke text and add to path for clipping.
|
387
|
+
#
|
388
|
+
# Specify as 5 or :stroke_clip.
|
389
|
+
#
|
390
|
+
# #>pdf-small-hide
|
391
|
+
# canvas.font("Helvetica", size: 13)
|
392
|
+
# canvas.stroke_color("green").line_width(0.5)
|
393
|
+
# canvas.text_rendering_mode(:stroke_clip)
|
394
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
395
|
+
# canvas.stroke_color("red").line_width(20).line(30, 20, 30, 80).stroke
|
291
396
|
STROKE_CLIP = NamedValue.new(:stroke_clip, 5)
|
292
397
|
|
293
|
-
# Fill, then stroke text and add to path for clipping
|
398
|
+
# Fill, then stroke text and add to path for clipping.
|
399
|
+
#
|
400
|
+
# Specify as 6 or :fill_stroke_clip.
|
401
|
+
#
|
402
|
+
# #>pdf-small-hide
|
403
|
+
# canvas.font("Helvetica", size: 13)
|
404
|
+
# canvas.stroke_color("green").line_width(0.5)
|
405
|
+
# canvas.text_rendering_mode(:fill_stroke_clip)
|
406
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
407
|
+
# canvas.stroke_color("red").line_width(20).line(30, 20, 30, 80).stroke
|
294
408
|
FILL_STROKE_CLIP = NamedValue.new(:fill_stroke_clip, 6)
|
295
409
|
|
296
|
-
# Add text to path for clipping
|
410
|
+
# Add text to path for clipping.
|
411
|
+
#
|
412
|
+
# Specify as 7 or :clip.
|
413
|
+
#
|
414
|
+
# #>pdf-small-hide
|
415
|
+
# canvas.font("Helvetica", size: 13)
|
416
|
+
# canvas.stroke_color("green").line_width(0.5)
|
417
|
+
# canvas.text_rendering_mode(:clip)
|
418
|
+
# canvas.text("#{canvas.text_rendering_mode.name}", at: [10, 50])
|
419
|
+
# canvas.stroke_color("red").line_width(20).line(30, 20, 30, 80).stroke
|
297
420
|
CLIP = NamedValue.new(:clip, 7)
|
298
421
|
|
299
422
|
end
|
@@ -415,21 +538,21 @@ module HexaPDF
|
|
415
538
|
|
416
539
|
# The scaled character spacing used in glyph displacement calculations.
|
417
540
|
#
|
418
|
-
# This returns the
|
541
|
+
# This returns the character spacing multiplied by #scaled_horizontal_scaling.
|
419
542
|
#
|
420
543
|
# See PDF1.7 s9.4.4
|
421
544
|
attr_reader :scaled_character_spacing
|
422
545
|
|
423
546
|
# The scaled word spacing used in glyph displacement calculations.
|
424
547
|
#
|
425
|
-
# This returns the
|
548
|
+
# This returns the word spacing multiplied by #scaled_horizontal_scaling.
|
426
549
|
#
|
427
550
|
# See PDF1.7 s9.4.4
|
428
551
|
attr_reader :scaled_word_spacing
|
429
552
|
|
430
553
|
# The scaled font size used in glyph displacement calculations.
|
431
554
|
#
|
432
|
-
# This returns the
|
555
|
+
# This returns the font size divided by 1000 multiplied by #scaled_horizontal_scaling.
|
433
556
|
#
|
434
557
|
# See PDF1.7 s9.4.4
|
435
558
|
attr_reader :scaled_font_size
|
@@ -293,7 +293,7 @@ module HexaPDF
|
|
293
293
|
end
|
294
294
|
|
295
295
|
# :nodoc:
|
296
|
-
DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d\d)(?:'|'(\d
|
296
|
+
DATE_RE = /\AD:(\d{4})(\d\d)?(\d\d)?(\d\d)?(\d\d)?(\d\d)?([Z+-])?(?:(\d\d)(?:'|'([0-5]\d)'?|\z)?)?\z/n
|
297
297
|
|
298
298
|
# Checks if the given object is a string and converts into a Time object if possible.
|
299
299
|
# Otherwise returns +nil+.
|
@@ -72,8 +72,19 @@ module HexaPDF
|
|
72
72
|
# Compresses the content streams of all pages if set to +true+. Note that this can take a
|
73
73
|
# *very* long time because each content stream has to be unfiltered, parsed, serialized
|
74
74
|
# and then filtered again.
|
75
|
+
#
|
76
|
+
# prune_page_resources::
|
77
|
+
# Removes all unused XObjects from the resources dictionaries of all pages. It is
|
78
|
+
# recommended to also set the +compact+ argument because otherwise the unused XObjects won't
|
79
|
+
# be deleted from the document.
|
80
|
+
#
|
81
|
+
# This is sometimes necessary after importing pages from other PDF files that use a single
|
82
|
+
# resources dictionary for all pages.
|
75
83
|
def self.call(doc, compact: false, object_streams: :preserve, xref_streams: :preserve,
|
76
|
-
compress_pages: false)
|
84
|
+
compress_pages: false, prune_page_resources: false)
|
85
|
+
used_refs = compress_pages(doc) if compress_pages
|
86
|
+
prune_page_resources(doc, used_refs) if prune_page_resources
|
87
|
+
|
77
88
|
if compact
|
78
89
|
compact(doc, object_streams, xref_streams)
|
79
90
|
elsif object_streams != :preserve
|
@@ -83,8 +94,6 @@ module HexaPDF
|
|
83
94
|
else
|
84
95
|
doc.each(only_current: false, &method(:delete_fields_with_defaults))
|
85
96
|
end
|
86
|
-
|
87
|
-
compress_pages(doc) if compress_pages
|
88
97
|
end
|
89
98
|
|
90
99
|
# Compacts the document by merging all revisions into one, deleting null and unused entries
|
@@ -214,12 +223,41 @@ module HexaPDF
|
|
214
223
|
|
215
224
|
# Compresses the contents of all pages by parsing and then serializing again. The HexaPDF
|
216
225
|
# serializer is already optimized for small output size so nothing else needs to be done.
|
226
|
+
#
|
227
|
+
# Returns a hash of the form key=>true where the keys are the used XObjects (for use with
|
228
|
+
# #prune_page_resources).
|
217
229
|
def self.compress_pages(doc)
|
230
|
+
used_refs = {}
|
218
231
|
doc.pages.each do |page|
|
219
232
|
processor = SerializationProcessor.new
|
220
233
|
HexaPDF::Content::Parser.parse(page.contents, processor)
|
221
234
|
page.contents = processor.result
|
222
235
|
page[:Contents].set_filter(:FlateDecode)
|
236
|
+
xobjects = page.resources[:XObject]
|
237
|
+
processor.used_references.each {|ref| used_refs[xobjects[ref]] = true }
|
238
|
+
end
|
239
|
+
used_refs
|
240
|
+
end
|
241
|
+
|
242
|
+
# Deletes all XObject entries from the resources dictionaries of all pages whose names do not
|
243
|
+
# match the keys in +used_refs+.
|
244
|
+
def self.prune_page_resources(doc, used_refs)
|
245
|
+
unless used_refs
|
246
|
+
used_refs = {}
|
247
|
+
doc.pages.each do |page|
|
248
|
+
xobjects = page.resources[:XObject]
|
249
|
+
HexaPDF::Content::Parser.parse(page.contents) do |op, operands|
|
250
|
+
used_refs[xobjects[operands[0]]] = true if op == :Do
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
doc.pages.each do |page|
|
256
|
+
xobjects = page.resources[:XObject]
|
257
|
+
xobjects.each do |key, obj|
|
258
|
+
next if used_refs[obj]
|
259
|
+
xobjects.delete(key)
|
260
|
+
end
|
223
261
|
end
|
224
262
|
end
|
225
263
|
|
@@ -228,14 +266,19 @@ module HexaPDF
|
|
228
266
|
|
229
267
|
attr_reader :result #:nodoc:
|
230
268
|
|
269
|
+
# Contains all found references
|
270
|
+
attr_reader :used_references
|
271
|
+
|
231
272
|
def initialize #:nodoc:
|
232
273
|
@result = ''.b
|
233
274
|
@serializer = HexaPDF::Serializer.new
|
275
|
+
@used_references = []
|
234
276
|
end
|
235
277
|
|
236
278
|
def process(op, operands) #:nodoc:
|
237
279
|
@result << HexaPDF::Content::Operator::DEFAULT_OPERATORS[op].
|
238
280
|
serialize(@serializer, *operands)
|
281
|
+
@used_references << operands[0] if op == :Do
|
239
282
|
end
|
240
283
|
|
241
284
|
end
|
data/lib/hexapdf/version.rb
CHANGED
@@ -0,0 +1,171 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
# See https://www.feistyduck.com/library/openssl-cookbook/online/ch-openssl.html
|
3
|
+
|
4
|
+
|
5
|
+
#####################################3
|
6
|
+
# Root CA
|
7
|
+
mkdir root-ca
|
8
|
+
cd root-ca
|
9
|
+
mkdir certs db private
|
10
|
+
touch db/index
|
11
|
+
openssl rand -hex 16 > db/serial
|
12
|
+
echo 1001 > db/crlnumber
|
13
|
+
|
14
|
+
cat > root-ca.conf <<'CACONF'
|
15
|
+
[default]
|
16
|
+
name = root-ca
|
17
|
+
domain_suffix = hexapdf.gettalong.org
|
18
|
+
aia_url = http://$name.$domain_suffix/$name.crt
|
19
|
+
crl_url = http://$name.$domain_suffix/$name.crl
|
20
|
+
default_ca = ca_default
|
21
|
+
name_opt = utf8,esc_ctrl,multiline,lname,align
|
22
|
+
|
23
|
+
[ca_dn]
|
24
|
+
countryName = "AT"
|
25
|
+
organizationName = "HexaPDF"
|
26
|
+
commonName = "HexaPDF Test Root CA"
|
27
|
+
|
28
|
+
[ca_default]
|
29
|
+
home = ../root-ca
|
30
|
+
database = $home/db/index
|
31
|
+
serial = $home/db/serial
|
32
|
+
crlnumber = $home/db/crlnumber
|
33
|
+
certificate = $home/$name.crt
|
34
|
+
private_key = $home/private/$name.key
|
35
|
+
RANDFILE = $home/private/random
|
36
|
+
new_certs_dir = $home/certs
|
37
|
+
unique_subject = no
|
38
|
+
copy_extensions = none
|
39
|
+
default_days = 36500
|
40
|
+
default_crl_days = 365
|
41
|
+
default_md = sha256
|
42
|
+
policy = policy_c_o_match
|
43
|
+
|
44
|
+
[policy_c_o_match]
|
45
|
+
countryName = match
|
46
|
+
stateOrProvinceName = optional
|
47
|
+
organizationName = match
|
48
|
+
organizationalUnitName = optional
|
49
|
+
commonName = supplied
|
50
|
+
emailAddress = optional
|
51
|
+
|
52
|
+
[req]
|
53
|
+
default_bits = 4096
|
54
|
+
encrypt_key = no
|
55
|
+
default_md = sha256
|
56
|
+
utf8 = yes
|
57
|
+
string_mask = utf8only
|
58
|
+
prompt = no
|
59
|
+
distinguished_name = ca_dn
|
60
|
+
req_extensions = ca_ext
|
61
|
+
|
62
|
+
[ca_ext]
|
63
|
+
basicConstraints = critical,CA:true
|
64
|
+
keyUsage = critical,keyCertSign,cRLSign
|
65
|
+
subjectKeyIdentifier = hash
|
66
|
+
|
67
|
+
[sub_ca_ext]
|
68
|
+
authorityKeyIdentifier = keyid:always
|
69
|
+
basicConstraints = critical,CA:true,pathlen:0
|
70
|
+
extendedKeyUsage = clientAuth,serverAuth
|
71
|
+
keyUsage = critical,keyCertSign,cRLSign
|
72
|
+
subjectKeyIdentifier = hash
|
73
|
+
|
74
|
+
[client_ext]
|
75
|
+
authorityKeyIdentifier = keyid:always
|
76
|
+
basicConstraints = critical,CA:false
|
77
|
+
extendedKeyUsage = clientAuth
|
78
|
+
keyUsage = critical,digitalSignature
|
79
|
+
subjectKeyIdentifier = hash
|
80
|
+
CACONF
|
81
|
+
|
82
|
+
openssl req -new -config root-ca.conf -out root-ca.csr -keyout private/root-ca.key
|
83
|
+
openssl ca -selfsign -config root-ca.conf -batch -in root-ca.csr -out root-ca.crt -extensions ca_ext
|
84
|
+
|
85
|
+
#####################################3
|
86
|
+
# Subordinate CA
|
87
|
+
cd ..
|
88
|
+
mkdir sub-ca
|
89
|
+
cd sub-ca
|
90
|
+
mkdir certs db private
|
91
|
+
touch db/index
|
92
|
+
openssl rand -hex 16 > db/serial
|
93
|
+
echo 1001 > db/crlnumber
|
94
|
+
|
95
|
+
cat > sub-ca.conf <<'CACONF'
|
96
|
+
[default]
|
97
|
+
name = sub-ca
|
98
|
+
domain_suffix = hexapdf.gettalong.org
|
99
|
+
aia_url = http://$name.$domain_suffix/$name.crt
|
100
|
+
crl_url = http://$name.$domain_suffix/$name.crl
|
101
|
+
default_ca = ca_default
|
102
|
+
name_opt = utf8,esc_ctrl,multiline,lname,align
|
103
|
+
|
104
|
+
[ca_dn]
|
105
|
+
countryName = "AT"
|
106
|
+
organizationName = "HexaPDF"
|
107
|
+
commonName = "HexaPDF Test Subordinate CA"
|
108
|
+
|
109
|
+
[ca_default]
|
110
|
+
home = ../sub-ca
|
111
|
+
database = $home/db/index
|
112
|
+
serial = $home/db/serial
|
113
|
+
crlnumber = $home/db/crlnumber
|
114
|
+
certificate = $home/$name.crt
|
115
|
+
private_key = $home/private/$name.key
|
116
|
+
RANDFILE = $home/private/random
|
117
|
+
new_certs_dir = $home/certs
|
118
|
+
unique_subject = no
|
119
|
+
copy_extensions = copy
|
120
|
+
default_days = 36500
|
121
|
+
default_crl_days = 90
|
122
|
+
default_md = sha256
|
123
|
+
policy = policy_c_o_match
|
124
|
+
|
125
|
+
[policy_c_o_match]
|
126
|
+
countryName = match
|
127
|
+
stateOrProvinceName = optional
|
128
|
+
organizationName = match
|
129
|
+
organizationalUnitName = optional
|
130
|
+
commonName = supplied
|
131
|
+
emailAddress = optional
|
132
|
+
|
133
|
+
[req]
|
134
|
+
default_bits = 4096
|
135
|
+
encrypt_key = no
|
136
|
+
default_md = sha256
|
137
|
+
utf8 = yes
|
138
|
+
string_mask = utf8only
|
139
|
+
prompt = no
|
140
|
+
distinguished_name = ca_dn
|
141
|
+
req_extensions = ca_ext
|
142
|
+
|
143
|
+
[ca_ext]
|
144
|
+
basicConstraints = critical,CA:true
|
145
|
+
keyUsage = critical,keyCertSign,cRLSign
|
146
|
+
subjectKeyIdentifier = hash
|
147
|
+
|
148
|
+
[sub_ca_ext]
|
149
|
+
authorityKeyIdentifier = keyid:always
|
150
|
+
basicConstraints = critical,CA:true,pathlen:0
|
151
|
+
extendedKeyUsage = clientAuth,serverAuth
|
152
|
+
keyUsage = critical,keyCertSign,cRLSign
|
153
|
+
subjectKeyIdentifier = hash
|
154
|
+
|
155
|
+
[client_ext]
|
156
|
+
authorityKeyIdentifier = keyid:always
|
157
|
+
basicConstraints = critical,CA:false
|
158
|
+
extendedKeyUsage = clientAuth
|
159
|
+
keyUsage = critical,digitalSignature
|
160
|
+
subjectKeyIdentifier = hash
|
161
|
+
CACONF
|
162
|
+
|
163
|
+
openssl req -new -config sub-ca.conf -out sub-ca.csr -keyout private/sub-ca.key
|
164
|
+
openssl ca -config ../root-ca/root-ca.conf -batch -in sub-ca.csr -out sub-ca.crt -extensions sub_ca_ext
|
165
|
+
|
166
|
+
|
167
|
+
#####################################3
|
168
|
+
# Signing certificate
|
169
|
+
openssl req -new -config sub-ca.conf -subj "/C=AT/O=HexaPDF/CN=HexaPDF Test Certifcate" -keyout private/signing.key -out signing.csr
|
170
|
+
openssl ca -config sub-ca.conf -in signing.csr -batch -out signing.crt -extensions client_ext
|
171
|
+
openssl pkcs12 -export -in signing.crt -inkey private/signing.key -password pass: -out signing.p12
|