prawn 2.3.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/prawn/document/bounding_box.rb +223 -143
- data/lib/prawn/document/column_box.rb +61 -26
- data/lib/prawn/document/internals.rb +25 -16
- data/lib/prawn/document/span.rb +21 -18
- data/lib/prawn/document.rb +273 -182
- data/lib/prawn/encoding.rb +2 -5
- data/lib/prawn/errors.rb +23 -34
- data/lib/prawn/font.rb +254 -139
- data/lib/prawn/font_metric_cache.rb +18 -16
- data/lib/prawn/fonts/afm.rb +99 -57
- data/lib/prawn/fonts/dfont.rb +7 -1
- data/lib/prawn/fonts/otf.rb +4 -1
- data/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
- data/lib/prawn/fonts/ttc.rb +7 -2
- data/lib/prawn/fonts/ttf.rb +345 -107
- data/lib/prawn/fonts.rb +14 -0
- data/lib/prawn/graphics/blend_mode.rb +25 -28
- data/lib/prawn/graphics/cap_style.rb +9 -12
- data/lib/prawn/graphics/color.rb +75 -50
- data/lib/prawn/graphics/dash.rb +45 -42
- data/lib/prawn/graphics/join_style.rb +18 -12
- data/lib/prawn/graphics/patterns.rb +239 -110
- data/lib/prawn/graphics/transformation.rb +51 -44
- data/lib/prawn/graphics/transparency.rb +16 -40
- data/lib/prawn/graphics.rb +370 -260
- data/lib/prawn/grid.rb +219 -57
- data/lib/prawn/image_handler.rb +27 -10
- data/lib/prawn/images/image.rb +8 -10
- data/lib/prawn/images/jpg.rb +46 -20
- data/lib/prawn/images/png.rb +94 -42
- data/lib/prawn/images.rb +70 -81
- data/lib/prawn/measurement_extensions.rb +39 -8
- data/lib/prawn/measurements.rb +60 -5
- data/lib/prawn/outline.rb +120 -113
- data/lib/prawn/repeater.rb +52 -36
- data/lib/prawn/security/arcfour.rb +4 -4
- data/lib/prawn/security.rb +106 -98
- data/lib/prawn/soft_mask.rb +42 -30
- data/lib/prawn/stamp.rb +38 -42
- data/lib/prawn/text/box.rb +156 -105
- data/lib/prawn/text/formatted/arranger.rb +121 -41
- data/lib/prawn/text/formatted/box.rb +239 -163
- data/lib/prawn/text/formatted/fragment.rb +130 -14
- data/lib/prawn/text/formatted/line_wrap.rb +49 -38
- data/lib/prawn/text/formatted/parser.rb +116 -74
- data/lib/prawn/text/formatted/wrap.rb +25 -26
- data/lib/prawn/text/formatted.rb +75 -0
- data/lib/prawn/text.rb +456 -211
- data/lib/prawn/transformation_stack.rb +29 -10
- data/lib/prawn/utilities.rb +13 -13
- data/lib/prawn/version.rb +2 -1
- data/lib/prawn/view.rb +69 -54
- data/lib/prawn.rb +24 -18
- data.tar.gz.sig +0 -0
- metadata +55 -262
- metadata.gz.sig +3 -4
- data/.yardopts +0 -10
- data/Gemfile +0 -5
- data/Rakefile +0 -54
- data/manual/absolute_position.pdf +0 -0
- data/manual/basic_concepts/adding_pages.rb +0 -26
- data/manual/basic_concepts/basic_concepts.rb +0 -43
- data/manual/basic_concepts/creation.rb +0 -38
- data/manual/basic_concepts/cursor.rb +0 -32
- data/manual/basic_concepts/measurement.rb +0 -24
- data/manual/basic_concepts/origin.rb +0 -37
- data/manual/basic_concepts/other_cursor_helpers.rb +0 -39
- data/manual/basic_concepts/view.rb +0 -48
- data/manual/bounding_box/bounding_box.rb +0 -41
- data/manual/bounding_box/bounds.rb +0 -48
- data/manual/bounding_box/canvas.rb +0 -23
- data/manual/bounding_box/creation.rb +0 -22
- data/manual/bounding_box/indentation.rb +0 -45
- data/manual/bounding_box/nesting.rb +0 -52
- data/manual/bounding_box/russian_boxes.rb +0 -40
- data/manual/bounding_box/stretchy.rb +0 -29
- data/manual/contents.rb +0 -35
- data/manual/cover.rb +0 -43
- data/manual/document_and_page_options/background.rb +0 -25
- data/manual/document_and_page_options/document_and_page_options.rb +0 -34
- data/manual/document_and_page_options/metadata.rb +0 -25
- data/manual/document_and_page_options/page_margins.rb +0 -36
- data/manual/document_and_page_options/page_size.rb +0 -34
- data/manual/document_and_page_options/print_scaling.rb +0 -22
- data/manual/example_helper.rb +0 -8
- data/manual/graphics/blend_mode.rb +0 -52
- data/manual/graphics/circle_and_ellipse.rb +0 -21
- data/manual/graphics/color.rb +0 -22
- data/manual/graphics/common_lines.rb +0 -29
- data/manual/graphics/fill_and_stroke.rb +0 -41
- data/manual/graphics/fill_rules.rb +0 -37
- data/manual/graphics/gradients.rb +0 -43
- data/manual/graphics/graphics.rb +0 -64
- data/manual/graphics/helper.rb +0 -27
- data/manual/graphics/line_width.rb +0 -36
- data/manual/graphics/lines_and_curves.rb +0 -40
- data/manual/graphics/polygon.rb +0 -27
- data/manual/graphics/rectangle.rb +0 -20
- data/manual/graphics/rotate.rb +0 -25
- data/manual/graphics/scale.rb +0 -42
- data/manual/graphics/soft_masks.rb +0 -44
- data/manual/graphics/stroke_cap.rb +0 -30
- data/manual/graphics/stroke_dash.rb +0 -47
- data/manual/graphics/stroke_join.rb +0 -29
- data/manual/graphics/translate.rb +0 -28
- data/manual/graphics/transparency.rb +0 -33
- data/manual/how_to_read_this_manual.rb +0 -39
- data/manual/images/absolute_position.rb +0 -22
- data/manual/images/fit.rb +0 -20
- data/manual/images/horizontal.rb +0 -24
- data/manual/images/images.rb +0 -41
- data/manual/images/plain_image.rb +0 -17
- data/manual/images/scale.rb +0 -21
- data/manual/images/vertical.rb +0 -27
- data/manual/images/width_and_height.rb +0 -24
- data/manual/layout/boxes.rb +0 -26
- data/manual/layout/content.rb +0 -24
- data/manual/layout/layout.rb +0 -27
- data/manual/layout/simple_grid.rb +0 -22
- data/manual/outline/add_subsection_to.rb +0 -60
- data/manual/outline/insert_section_after.rb +0 -46
- data/manual/outline/outline.rb +0 -33
- data/manual/outline/sections_and_pages.rb +0 -66
- data/manual/repeatable_content/alternate_page_numbering.rb +0 -36
- data/manual/repeatable_content/page_numbering.rb +0 -55
- data/manual/repeatable_content/repeatable_content.rb +0 -35
- data/manual/repeatable_content/repeater.rb +0 -54
- data/manual/repeatable_content/stamp.rb +0 -40
- data/manual/security/encryption.rb +0 -28
- data/manual/security/permissions.rb +0 -41
- data/manual/security/security.rb +0 -28
- data/manual/table.rb +0 -16
- data/manual/text/alignment.rb +0 -43
- data/manual/text/color.rb +0 -24
- data/manual/text/column_box.rb +0 -30
- data/manual/text/fallback_fonts.rb +0 -41
- data/manual/text/font.rb +0 -40
- data/manual/text/font_size.rb +0 -44
- data/manual/text/font_style.rb +0 -22
- data/manual/text/formatted_callbacks.rb +0 -65
- data/manual/text/formatted_text.rb +0 -58
- data/manual/text/free_flowing_text.rb +0 -50
- data/manual/text/inline.rb +0 -40
- data/manual/text/kerning_and_character_spacing.rb +0 -38
- data/manual/text/leading.rb +0 -24
- data/manual/text/line_wrapping.rb +0 -60
- data/manual/text/paragraph_indentation.rb +0 -32
- data/manual/text/positioned_text.rb +0 -37
- data/manual/text/registering_families.rb +0 -51
- data/manual/text/rendering_and_color.rb +0 -36
- data/manual/text/right_to_left_text.rb +0 -54
- data/manual/text/rotation.rb +0 -47
- data/manual/text/single_usage.rb +0 -36
- data/manual/text/text.rb +0 -75
- data/manual/text/text_box_excess.rb +0 -35
- data/manual/text/text_box_extensions.rb +0 -48
- data/manual/text/text_box_overflow.rb +0 -49
- data/manual/text/utf8.rb +0 -27
- data/manual/text/win_ansi_charset.rb +0 -62
- data/prawn.gemspec +0 -57
- data/spec/data/curves.pdf +0 -66
- data/spec/extensions/encoding_helpers.rb +0 -11
- data/spec/prawn/document/bounding_box_spec.rb +0 -546
- data/spec/prawn/document/column_box_spec.rb +0 -75
- data/spec/prawn/document/security_spec.rb +0 -176
- data/spec/prawn/document_annotations_spec.rb +0 -76
- data/spec/prawn/document_destinations_spec.rb +0 -15
- data/spec/prawn/document_grid_spec.rb +0 -99
- data/spec/prawn/document_reference_spec.rb +0 -27
- data/spec/prawn/document_span_spec.rb +0 -36
- data/spec/prawn/document_spec.rb +0 -802
- data/spec/prawn/font_metric_cache_spec.rb +0 -54
- data/spec/prawn/font_spec.rb +0 -542
- data/spec/prawn/graphics/blend_mode_spec.rb +0 -63
- data/spec/prawn/graphics/transparency_spec.rb +0 -81
- data/spec/prawn/graphics_spec.rb +0 -837
- data/spec/prawn/graphics_stroke_styles_spec.rb +0 -229
- data/spec/prawn/image_handler_spec.rb +0 -53
- data/spec/prawn/images/jpg_spec.rb +0 -20
- data/spec/prawn/images/png_spec.rb +0 -283
- data/spec/prawn/images_spec.rb +0 -224
- data/spec/prawn/measurements_extensions_spec.rb +0 -24
- data/spec/prawn/outline_spec.rb +0 -412
- data/spec/prawn/repeater_spec.rb +0 -165
- data/spec/prawn/soft_mask_spec.rb +0 -74
- data/spec/prawn/stamp_spec.rb +0 -172
- data/spec/prawn/text/box_spec.rb +0 -1112
- data/spec/prawn/text/formatted/arranger_spec.rb +0 -466
- data/spec/prawn/text/formatted/box_spec.rb +0 -846
- data/spec/prawn/text/formatted/fragment_spec.rb +0 -343
- data/spec/prawn/text/formatted/line_wrap_spec.rb +0 -494
- data/spec/prawn/text/formatted/parser_spec.rb +0 -697
- data/spec/prawn/text_draw_text_spec.rb +0 -149
- data/spec/prawn/text_rendering_mode_spec.rb +0 -48
- data/spec/prawn/text_spacing_spec.rb +0 -95
- data/spec/prawn/text_spec.rb +0 -603
- data/spec/prawn/text_with_inline_formatting_spec.rb +0 -35
- data/spec/prawn/transformation_stack_spec.rb +0 -66
- data/spec/prawn/view_spec.rb +0 -63
- data/spec/prawn_manual_spec.rb +0 -35
- data/spec/spec_helper.rb +0 -48
data/lib/prawn/security.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# encryption.rb : Implements encrypted PDF and access permissions.
|
4
|
-
#
|
5
|
-
# Copyright August 2008, Brad Ediger. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
|
9
3
|
require 'digest/md5'
|
10
4
|
|
11
5
|
require_relative 'security/arcfour'
|
@@ -18,76 +12,71 @@ module Prawn
|
|
18
12
|
# @group Experimental API
|
19
13
|
|
20
14
|
# Encrypts the document, to protect confidential data or control
|
21
|
-
# modifications to the document. The encryption algorithm used is
|
22
|
-
#
|
15
|
+
# modifications to the document. The encryption algorithm used is detailed
|
16
|
+
# in the PDF Reference 1.3, section 3.5 "Encryption", and it is
|
23
17
|
# implemented by all major PDF readers.
|
24
18
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
# <tt>:user_password</tt>:: Password required to open the document. If
|
28
|
-
# this is omitted or empty, no password will be
|
29
|
-
# required. The document will still be
|
30
|
-
# encrypted, but anyone can read it.
|
31
|
-
#
|
32
|
-
# <tt>:owner_password</tt>:: Password required to make modifications to
|
33
|
-
# the document or change or override its
|
34
|
-
# permissions. If this is set to
|
35
|
-
# <tt>:random</tt>, a random password will be
|
36
|
-
# used; this can be useful if you never want
|
37
|
-
# users to be able to override the document
|
38
|
-
# permissions.
|
39
|
-
#
|
40
|
-
# <tt>:permissions</tt>:: A hash mapping permission symbols (see below) to
|
41
|
-
# <tt>true</tt> or <tt>false</tt>. True means
|
42
|
-
# "permitted", and false means "not permitted".
|
43
|
-
# All permissions default to <tt>true</tt>.
|
44
|
-
#
|
45
|
-
# The following permissions can be specified:
|
46
|
-
#
|
47
|
-
# <tt>:print_document</tt>:: Print document.
|
48
|
-
#
|
49
|
-
# <tt>:modify_contents</tt>:: Modify contents of document (other than text
|
50
|
-
# annotations and interactive form fields).
|
51
|
-
#
|
52
|
-
# <tt>:copy_contents</tt>:: Copy text and graphics from document.
|
53
|
-
#
|
54
|
-
# <tt>:modify_annotations</tt>:: Add or modify text annotations and
|
55
|
-
# interactive form fields.
|
56
|
-
#
|
57
|
-
# == Examples
|
19
|
+
# #### Examples
|
58
20
|
#
|
59
21
|
# Deny printing to everyone, but allow anyone to open without a password:
|
60
22
|
#
|
61
|
-
#
|
62
|
-
#
|
23
|
+
# ```ruby
|
24
|
+
# encrypt_document permissions: { print_document: false },
|
25
|
+
# owner_password: :random
|
26
|
+
# ```
|
63
27
|
#
|
64
28
|
# Set a user and owner password on the document, with full permissions for
|
65
29
|
# both the user and the owner:
|
66
30
|
#
|
67
|
-
#
|
31
|
+
# ```ruby
|
32
|
+
# encrypt_document user_password: 'foo', owner_password: 'bar'
|
33
|
+
# ```
|
68
34
|
#
|
69
35
|
# Set no passwords, grant all permissions (This is useful because the
|
70
36
|
# default in some readers, if no permissions are specified, is "deny"):
|
71
37
|
#
|
72
|
-
#
|
38
|
+
# ```ruby
|
39
|
+
# encrypt_document
|
40
|
+
# ```
|
73
41
|
#
|
74
|
-
#
|
42
|
+
# #### Caveats
|
75
43
|
#
|
76
44
|
# * The encryption used is weak; the key is password-derived and is
|
77
45
|
# limited to 40 bits, due to US export controls in effect at the time
|
78
46
|
# the PDF standard was written.
|
79
|
-
#
|
80
47
|
# * There is nothing technologically requiring PDF readers to respect the
|
81
48
|
# permissions embedded in a document. Many PDF readers do not.
|
82
|
-
#
|
83
|
-
# * In short, you have <b>no security at all</b> against a moderately
|
49
|
+
# * In short, you have **no security at all** against a moderately
|
84
50
|
# motivated person. Don't use this for anything super-serious. This is
|
85
51
|
# not a limitation of Prawn, but is rather a built-in limitation of the
|
86
52
|
# PDF format.
|
87
53
|
#
|
54
|
+
# @param options [Hash{Symbol => any}]
|
55
|
+
# @option options :user_password [String]
|
56
|
+
# Password required to open the document. If this is omitted or empty,
|
57
|
+
# no password will be required. The document will still be encrypted,
|
58
|
+
# but anyone can read it.
|
59
|
+
# @option options :owner_password [String, :random]
|
60
|
+
# Password required to make modifications to the document or change or
|
61
|
+
# override its permissions. If this is set to `:random`, a random
|
62
|
+
# password will be used; this can be useful if you never want users to
|
63
|
+
# be able to override the document permissions.
|
64
|
+
# @option options :permissions [Hash{Symbol => Boolean}]
|
65
|
+
# A hash mapping permission symbols (see below) to `true` or `false`.
|
66
|
+
# `true` means "permitted", and `false` means "not permitted". All
|
67
|
+
# permissions default to `true`.
|
68
|
+
#
|
69
|
+
# The following permissions can be specified:
|
70
|
+
#
|
71
|
+
# - `:print_document` -- Print document.
|
72
|
+
# - `:modify_contents` -- Modify contents of document (other than text
|
73
|
+
# annotations and interactive form fields).
|
74
|
+
# - `:copy_contents` -- Copy text and graphics from document.
|
75
|
+
# - `:modify_annotations` -- Add or modify text annotations and
|
76
|
+
# interactive form fields.
|
77
|
+
# @return [void]
|
88
78
|
def encrypt_document(options = {})
|
89
|
-
Prawn.verify_options
|
90
|
-
options
|
79
|
+
Prawn.verify_options(%i[user_password owner_password permissions], options)
|
91
80
|
@user_password = options.delete(:user_password) || ''
|
92
81
|
|
93
82
|
@owner_password = options.delete(:owner_password) || @user_password
|
@@ -104,9 +93,16 @@ module Prawn
|
|
104
93
|
state.encryption_key = user_encryption_key
|
105
94
|
end
|
106
95
|
|
107
|
-
# Encrypts the given string under the given key, also requiring the
|
108
|
-
#
|
96
|
+
# Encrypts the given string under the given key, also requiring the object
|
97
|
+
# ID and generation number of the reference.
|
98
|
+
#
|
109
99
|
# See Algorithm 3.1.
|
100
|
+
#
|
101
|
+
# @param str [String]
|
102
|
+
# @param key [String]
|
103
|
+
# @param id [Integer]
|
104
|
+
# @param gen [Integer]
|
105
|
+
# @return [String]
|
110
106
|
def self.encrypt_string(str, key, id, gen)
|
111
107
|
# Convert ID and Gen number into little-endian truncated byte strings
|
112
108
|
id = [id].pack('V')[0, 3]
|
@@ -124,11 +120,11 @@ module Prawn
|
|
124
120
|
def encryption_dictionary
|
125
121
|
{
|
126
122
|
Filter: :Standard, # default PDF security handler
|
127
|
-
V: 1,
|
128
|
-
R: 2,
|
123
|
+
V: 1, # "Algorithm 3.1", PDF reference 1.3
|
124
|
+
R: 2, # Revision 2 of the algorithm
|
129
125
|
O: PDF::Core::ByteString.new(owner_password_hash),
|
130
126
|
U: PDF::Core::ByteString.new(user_password_hash),
|
131
|
-
P: permissions_value
|
127
|
+
P: permissions_value,
|
132
128
|
}
|
133
129
|
end
|
134
130
|
|
@@ -137,7 +133,7 @@ module Prawn
|
|
137
133
|
print_document: 3,
|
138
134
|
modify_contents: 4,
|
139
135
|
copy_contents: 5,
|
140
|
-
modify_annotations: 6
|
136
|
+
modify_annotations: 6,
|
141
137
|
}.freeze
|
142
138
|
private_constant :PERMISSIONS_BITS
|
143
139
|
|
@@ -151,7 +147,7 @@ module Prawn
|
|
151
147
|
raise(
|
152
148
|
ArgumentError,
|
153
149
|
"Unknown permission :#{key}. Valid options: " +
|
154
|
-
PERMISSIONS_BITS.keys.map(&:inspect).join(', ')
|
150
|
+
PERMISSIONS_BITS.keys.map(&:inspect).join(', '),
|
155
151
|
)
|
156
152
|
end
|
157
153
|
|
@@ -181,21 +177,23 @@ module Prawn
|
|
181
177
|
end
|
182
178
|
|
183
179
|
def user_encryption_key
|
184
|
-
@user_encryption_key ||=
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
180
|
+
@user_encryption_key ||=
|
181
|
+
begin
|
182
|
+
md5 = Digest::MD5.new
|
183
|
+
md5 << pad_password(@user_password)
|
184
|
+
md5 << owner_password_hash
|
185
|
+
md5 << [permissions_value].pack('V')
|
186
|
+
md5.digest[0, 5]
|
187
|
+
end
|
191
188
|
end
|
192
189
|
|
193
190
|
# The O (owner) value in the encryption dictionary. Algorithm 3.3.
|
194
191
|
def owner_password_hash
|
195
|
-
@owner_password_hash ||=
|
196
|
-
|
197
|
-
|
198
|
-
|
192
|
+
@owner_password_hash ||=
|
193
|
+
begin
|
194
|
+
key = Digest::MD5.digest(pad_password(@owner_password))[0, 5]
|
195
|
+
Arcfour.new(key).encrypt(pad_password(@user_password))
|
196
|
+
end
|
199
197
|
end
|
200
198
|
|
201
199
|
# The U (user) value in the encryption dictionary. Algorithm 3.4.
|
@@ -208,7 +206,7 @@ end
|
|
208
206
|
|
209
207
|
# @private
|
210
208
|
module PDF
|
211
|
-
module Core
|
209
|
+
module Core # rubocop: disable Style/Documentation
|
212
210
|
module_function
|
213
211
|
|
214
212
|
# Like pdf_object, but returns an encrypted result if required.
|
@@ -219,41 +217,41 @@ module PDF
|
|
219
217
|
def encrypted_pdf_object(obj, key, id, gen, in_content_stream = false)
|
220
218
|
case obj
|
221
219
|
when Array
|
222
|
-
|
220
|
+
array_content = obj.map { |e|
|
223
221
|
encrypted_pdf_object(e, key, id, gen, in_content_stream)
|
224
|
-
|
222
|
+
}.join(' ')
|
223
|
+
"[#{array_content}]"
|
225
224
|
when LiteralString
|
226
|
-
obj =
|
227
|
-
|
228
|
-
|
225
|
+
obj =
|
226
|
+
ByteString.new(
|
227
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen),
|
228
|
+
).gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
|
229
229
|
"(#{obj})"
|
230
230
|
when Time
|
231
|
-
obj = obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop
|
232
|
-
obj =
|
233
|
-
|
234
|
-
|
231
|
+
obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
|
232
|
+
obj =
|
233
|
+
ByteString.new(
|
234
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen),
|
235
|
+
).gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
|
235
236
|
"(#{obj})"
|
236
237
|
when String
|
237
238
|
pdf_object(
|
238
239
|
ByteString.new(
|
239
|
-
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
240
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen),
|
240
241
|
),
|
241
|
-
in_content_stream
|
242
|
+
in_content_stream,
|
242
243
|
)
|
243
244
|
when ::Hash
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
end.join('') +
|
253
|
-
'>>'
|
245
|
+
hash_content = obj.map { |k, v|
|
246
|
+
unless k.is_a?(String) || k.is_a?(Symbol)
|
247
|
+
raise PDF::Core::Errors::FailedObjectConversion,
|
248
|
+
'A PDF Dictionary must be keyed by names'
|
249
|
+
end
|
250
|
+
"#{pdf_object(k.to_sym, in_content_stream)} #{encrypted_pdf_object(v, key, id, gen, in_content_stream)}\n"
|
251
|
+
}.join('')
|
252
|
+
"<< #{hash_content}>>"
|
254
253
|
when NameTree::Value
|
255
|
-
pdf_object(obj.name)
|
256
|
-
encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)
|
254
|
+
"#{pdf_object(obj.name)} #{encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)}"
|
257
255
|
when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
|
258
256
|
encrypted_pdf_object(obj.to_hash, key, id, gen, in_content_stream)
|
259
257
|
else # delegate back to pdf_object
|
@@ -263,12 +261,19 @@ module PDF
|
|
263
261
|
|
264
262
|
# @private
|
265
263
|
class Stream
|
264
|
+
# Encrypt stream.
|
265
|
+
#
|
266
|
+
# @param key [String]
|
267
|
+
# @param id [Integer]
|
268
|
+
# @param gen [Integer]
|
269
|
+
# @return [String]
|
266
270
|
def encrypted_object(key, id, gen)
|
267
271
|
if filtered_stream
|
268
|
-
"stream\n
|
272
|
+
"stream\n#{
|
269
273
|
Prawn::Document::Security.encrypt_string(
|
270
|
-
filtered_stream, key, id, gen
|
271
|
-
)
|
274
|
+
filtered_stream, key, id, gen,
|
275
|
+
)
|
276
|
+
}\nendstream\n"
|
272
277
|
else
|
273
278
|
''
|
274
279
|
end
|
@@ -278,7 +283,10 @@ module PDF
|
|
278
283
|
# @private
|
279
284
|
class Reference
|
280
285
|
# Returns the object definition for the object this references, keyed from
|
281
|
-
#
|
286
|
+
# `key`.
|
287
|
+
#
|
288
|
+
# @param key [String]
|
289
|
+
# @return [String]
|
282
290
|
def encrypted_object(key)
|
283
291
|
@on_encode&.call(self)
|
284
292
|
|
@@ -288,7 +296,7 @@ module PDF
|
|
288
296
|
PDF::Core.encrypted_pdf_object(data, key, @identifier, gen) << "\n"
|
289
297
|
else
|
290
298
|
output << PDF::Core.encrypted_pdf_object(
|
291
|
-
data.merge(@stream.data), key, @identifier, gen
|
299
|
+
data.merge(@stream.data), key, @identifier, gen,
|
292
300
|
) << "\n" <<
|
293
301
|
@stream.encrypted_object(key, @identifier, gen)
|
294
302
|
end
|
data/lib/prawn/soft_mask.rb
CHANGED
@@ -1,32 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# soft_mask.rb : Implements soft-masking
|
4
|
-
#
|
5
|
-
# Copyright September 2012, Alexander Mankuta. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
#
|
9
|
-
|
10
3
|
module Prawn
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# You must group soft mask and graphics it's applied to under
|
15
|
-
# save_graphics_state because soft mask is a part of graphic state in PDF.
|
16
|
-
#
|
17
|
-
# Example:
|
18
|
-
# pdf.save_graphics_state do
|
19
|
-
# pdf.soft_mask do
|
20
|
-
# pdf.fill_color "444444"
|
21
|
-
# pdf.fill_polygon [0, 40], [60, 10], [120, 40], [60, 68]
|
22
|
-
# end
|
23
|
-
# pdf.fill_color '000000'
|
24
|
-
# pdf.fill_rectangle [0, 50], 120, 68
|
25
|
-
# end
|
26
|
-
#
|
4
|
+
# This module is used to create arbitrary transparency in document. Using
|
5
|
+
# a soft mask allows creating more visually rich documents.
|
27
6
|
module SoftMask
|
28
7
|
# @group Stable API
|
29
8
|
|
9
|
+
# Apply soft mask.
|
10
|
+
#
|
11
|
+
# You must group soft mask and graphics it's applied to under
|
12
|
+
# `save_graphics_state` because soft mask is a part of graphic state in PDF.
|
13
|
+
#
|
14
|
+
# Note that soft mask is applied only to the following content in the
|
15
|
+
# graphic state. Anything that comes before `soft_mask` is drawn without
|
16
|
+
# mask.
|
17
|
+
#
|
18
|
+
# Conceptually, soft mask is an alpha channel. Luminosity of the drawing in
|
19
|
+
# the soft mask defines the transparency of the drawing the mask is applied
|
20
|
+
# to. 0.0 mask luminosity ("black") results in a fully opaque target image and
|
21
|
+
# 1.0 mask luminosity ("white") results in a fully transparent target image.
|
22
|
+
# Grey values result in some semi-transparent target image.
|
23
|
+
#
|
24
|
+
# Note: you can use color in mask drawings but it makes harder to reason
|
25
|
+
# about the resulting value of alpha channel as it requires an additional
|
26
|
+
# luminosity calculation. However, this also allows achieving some advanced
|
27
|
+
# artistic effects (e.g. full-color photos in masks to get an effect similar
|
28
|
+
# to double exposure).
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# pdf.save_graphics_state do
|
32
|
+
# pdf.soft_mask do
|
33
|
+
# pdf.fill_color "444444"
|
34
|
+
# pdf.fill_polygon [0, 40], [60, 10], [120, 40], [60, 68]
|
35
|
+
# end
|
36
|
+
# pdf.fill_color '000000'
|
37
|
+
# pdf.fill_rectangle [0, 50], 120, 68
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# @yield Mask content.
|
41
|
+
# @return [void]
|
30
42
|
def soft_mask(&block)
|
31
43
|
renderer.min_version(1.4)
|
32
44
|
|
@@ -35,14 +47,14 @@ module Prawn
|
|
35
47
|
S: :Transparency,
|
36
48
|
CS: :DeviceRGB,
|
37
49
|
I: false,
|
38
|
-
K: false
|
50
|
+
K: false,
|
39
51
|
)
|
40
52
|
|
41
53
|
group = ref!(
|
42
54
|
Type: :XObject,
|
43
55
|
Subtype: :Form,
|
44
56
|
BBox: state.page.dimensions,
|
45
|
-
Group: group_attrs
|
57
|
+
Group: group_attrs,
|
46
58
|
)
|
47
59
|
|
48
60
|
state.page.stamp_stream(group, &block)
|
@@ -50,7 +62,7 @@ module Prawn
|
|
50
62
|
mask = ref!(
|
51
63
|
Type: :Mask,
|
52
64
|
S: :Luminosity,
|
53
|
-
G: group
|
65
|
+
G: group,
|
54
66
|
)
|
55
67
|
|
56
68
|
g_state = ref!(
|
@@ -62,17 +74,17 @@ module Prawn
|
|
62
74
|
OP: false,
|
63
75
|
op: false,
|
64
76
|
OPM: 1,
|
65
|
-
SA: true
|
77
|
+
SA: true,
|
66
78
|
)
|
67
79
|
|
68
80
|
registry_key = {
|
69
81
|
bbox: state.page.dimensions,
|
70
82
|
mask: [group.stream.filters.normalized, group.stream.filtered_stream],
|
71
|
-
page: state.page_count
|
83
|
+
page: state.page_count,
|
72
84
|
}.hash
|
73
85
|
|
74
86
|
if soft_mask_registry[registry_key]
|
75
|
-
renderer.add_content
|
87
|
+
renderer.add_content("/#{soft_mask_registry[registry_key]} gs")
|
76
88
|
else
|
77
89
|
masks = page.resources[:ExtGState] ||= {}
|
78
90
|
id = masks.empty? ? 'GS1' : masks.keys.max.succ
|
@@ -80,7 +92,7 @@ module Prawn
|
|
80
92
|
|
81
93
|
soft_mask_registry[registry_key] = id
|
82
94
|
|
83
|
-
renderer.add_content
|
95
|
+
renderer.add_content("/#{id} gs")
|
84
96
|
end
|
85
97
|
end
|
86
98
|
|
data/lib/prawn/stamp.rb
CHANGED
@@ -1,80 +1,76 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# stamp.rb : Implements a repeatable stamp
|
4
|
-
#
|
5
|
-
# Copyright October 2009, Daniel Nelson. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
#
|
9
3
|
module Prawn
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# element because the viewer application can cache the rendered
|
18
|
-
# results
|
4
|
+
# This module is used to create content that will be included multiple times
|
5
|
+
# in a document. Using a stamp has three advantages over creating content anew
|
6
|
+
# each time it is placed on the page:
|
7
|
+
# * Faster document creation.
|
8
|
+
# * Smaller final document.
|
9
|
+
# * Faster display on subsequent displays of the repeated element because the
|
10
|
+
# viewer application can cache the rendered results.
|
19
11
|
#
|
20
|
-
#
|
12
|
+
# @example
|
21
13
|
# pdf.create_stamp("my_stamp") {
|
22
14
|
# pdf.fill_circle([10, 15], 5)
|
23
|
-
# pdf.draw_text("hello world", :
|
15
|
+
# pdf.draw_text("hello world", at: [20, 10])
|
24
16
|
# }
|
25
17
|
# pdf.stamp("my_stamp")
|
26
|
-
#
|
27
18
|
module Stamp
|
28
19
|
# @group Stable API
|
29
20
|
|
30
|
-
# Renders the stamp
|
31
|
-
# raises <tt>Prawn::Errors::InvalidName</tt> if name.empty?
|
32
|
-
# raises <tt>Prawn::Errors::UndefinedObjectName</tt> if no stamp
|
33
|
-
# has been created with this name
|
21
|
+
# Renders the stamp.
|
34
22
|
#
|
35
|
-
#
|
23
|
+
# @example
|
36
24
|
# pdf.create_stamp("my_stamp") {
|
37
25
|
# pdf.fill_circle([10, 15], 5)
|
38
|
-
# pdf.text("hello world", :
|
26
|
+
# pdf.text("hello world", at: [20, 10])
|
39
27
|
# }
|
40
28
|
# pdf.stamp("my_stamp")
|
41
29
|
#
|
30
|
+
# @param name [String]
|
31
|
+
# @return [void]
|
32
|
+
# @raise [Prawn::Errors::InvalidName] if name is empty.
|
33
|
+
# @raise [Prawn::Errors::UndefinedObjectName] if no stamp has been created
|
34
|
+
# with this name.
|
42
35
|
def stamp(name)
|
43
36
|
dictionary_name, dictionary = stamp_dictionary(name)
|
44
|
-
renderer.add_content
|
45
|
-
update_annotation_references
|
37
|
+
renderer.add_content("/#{dictionary_name} Do")
|
38
|
+
update_annotation_references(dictionary.data[:Annots])
|
46
39
|
state.page.xobjects.merge!(dictionary_name => dictionary)
|
47
40
|
end
|
48
41
|
|
49
|
-
# Renders the stamp
|
50
|
-
# the
|
51
|
-
# created
|
42
|
+
# Renders the stamp at a position offset from the initial coords at which
|
43
|
+
# the elements of the stamp was created.
|
52
44
|
#
|
53
|
-
#
|
45
|
+
# @example
|
54
46
|
# pdf.create_stamp("circle") do
|
55
47
|
# pdf.fill_circle([0, 0], 25)
|
56
48
|
# end
|
57
49
|
# # draws a circle at 100, 100
|
58
50
|
# pdf.stamp_at("circle", [100, 100])
|
59
51
|
#
|
60
|
-
#
|
61
|
-
#
|
52
|
+
# @param name [String]
|
53
|
+
# @param point [Array(Number, Number)]
|
54
|
+
# @return [void]
|
55
|
+
# @see [stamp] for exceptions that might be raised.
|
62
56
|
def stamp_at(name, point)
|
63
57
|
translate(point[0], point[1]) { stamp(name) }
|
64
58
|
end
|
65
59
|
|
66
|
-
# Creates a re-usable stamp
|
67
|
-
#
|
68
|
-
# raises <tt>Prawn::Errors::NameTaken</tt> if a stamp already
|
69
|
-
# exists in this document with this name
|
70
|
-
# raises <tt>Prawn::Errors::InvalidName</tt> if name.empty?
|
60
|
+
# Creates a re-usable stamp.
|
71
61
|
#
|
72
|
-
#
|
62
|
+
# @example
|
73
63
|
# pdf.create_stamp("my_stamp") {
|
74
64
|
# pdf.fill_circle([10, 15], 5)
|
75
|
-
# pdf.draw_text("hello world", :
|
65
|
+
# pdf.draw_text("hello world", at: [20, 10])
|
76
66
|
# }
|
77
67
|
#
|
68
|
+
# @param name [String] Stamp name.
|
69
|
+
# @yield Stamp content.
|
70
|
+
# @return [void]
|
71
|
+
# @raise [Prawn::Errors::NameTaken]
|
72
|
+
# if a stamp already exists in this document with this name.
|
73
|
+
# @raise [Prawn::Errors::InvalidName] if name is empty.
|
78
74
|
def create_stamp(name, &block)
|
79
75
|
dictionary = create_stamp_dictionary(name)
|
80
76
|
|
@@ -116,15 +112,15 @@ module Prawn
|
|
116
112
|
Subtype: :Form,
|
117
113
|
BBox: [
|
118
114
|
0, 0,
|
119
|
-
state.page.dimensions[2], state.page.dimensions[3]
|
120
|
-
]
|
115
|
+
state.page.dimensions[2], state.page.dimensions[3],
|
116
|
+
],
|
121
117
|
)
|
122
118
|
|
123
119
|
dictionary_name = "Stamp#{next_stamp_dictionary_id}"
|
124
120
|
|
125
121
|
stamp_dictionary_registry[name] = {
|
126
122
|
stamp_dictionary_name: dictionary_name,
|
127
|
-
stamp_dictionary: dictionary
|
123
|
+
stamp_dictionary: dictionary,
|
128
124
|
}
|
129
125
|
dictionary
|
130
126
|
end
|