prawn 0.13.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.yardopts +10 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -16
- data/Rakefile +17 -39
- data/lib/prawn/document/bounding_box.rb +85 -42
- data/lib/prawn/document/column_box.rb +21 -11
- data/lib/prawn/document/internals.rb +40 -147
- data/lib/prawn/document/span.rb +25 -17
- data/lib/prawn/document.rb +286 -245
- data/lib/prawn/encoding.rb +68 -101
- data/lib/prawn/errors.rb +47 -43
- data/lib/prawn/font.rb +204 -155
- data/lib/prawn/font_metric_cache.rb +25 -21
- data/lib/prawn/fonts/afm.rb +292 -0
- data/lib/prawn/{font → fonts}/dfont.rb +7 -13
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +142 -80
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +6 -5
- data/lib/prawn/graphics/color.rb +47 -44
- data/lib/prawn/graphics/dash.rb +30 -13
- data/lib/prawn/graphics/join_style.rb +13 -6
- data/lib/prawn/graphics/patterns.rb +221 -90
- data/lib/prawn/graphics/transformation.rb +21 -12
- data/lib/prawn/graphics/transparency.rb +21 -17
- data/lib/prawn/graphics.rb +155 -128
- data/lib/prawn/{layout/grid.rb → grid.rb} +110 -47
- data/lib/prawn/image_handler.rb +16 -2
- data/lib/prawn/images/image.rb +4 -2
- data/lib/prawn/images/jpg.rb +39 -30
- data/lib/prawn/images/png.rb +132 -169
- data/lib/prawn/images.rb +70 -62
- data/lib/prawn/measurement_extensions.rb +15 -10
- data/lib/prawn/measurements.rb +22 -23
- data/lib/prawn/outline.rb +301 -13
- data/lib/prawn/repeater.rb +19 -17
- data/lib/prawn/security/arcfour.rb +54 -0
- data/lib/prawn/security.rb +108 -86
- data/lib/prawn/soft_mask.rb +40 -41
- data/lib/prawn/stamp.rb +29 -12
- data/lib/prawn/text/box.rb +27 -29
- data/lib/prawn/text/formatted/arranger.rb +110 -67
- data/lib/prawn/text/formatted/box.rb +233 -165
- data/lib/prawn/text/formatted/fragment.rb +27 -27
- data/lib/prawn/text/formatted/line_wrap.rb +137 -97
- data/lib/prawn/text/formatted/parser.rb +149 -127
- data/lib/prawn/text/formatted/wrap.rb +57 -37
- data/lib/prawn/text/formatted.rb +6 -4
- data/lib/prawn/text.rb +105 -73
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +11 -21
- data/lib/prawn/version.rb +5 -0
- data/lib/prawn/view.rb +101 -0
- data/lib/prawn.rb +42 -68
- data/{data/images/fractal.jpg → manual/absolute_position.pdf} +0 -0
- data/manual/basic_concepts/adding_pages.rb +9 -10
- data/manual/basic_concepts/basic_concepts.rb +33 -24
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +9 -10
- data/manual/basic_concepts/measurement.rb +10 -11
- data/manual/basic_concepts/origin.rb +8 -9
- data/manual/basic_concepts/other_cursor_helpers.rb +17 -18
- data/manual/basic_concepts/view.rb +48 -0
- data/manual/bounding_box/bounding_box.rb +31 -29
- data/manual/bounding_box/bounds.rb +17 -18
- data/manual/bounding_box/canvas.rb +8 -9
- data/manual/bounding_box/creation.rb +8 -9
- data/manual/bounding_box/indentation.rb +22 -23
- data/manual/bounding_box/nesting.rb +32 -25
- data/manual/bounding_box/russian_boxes.rb +19 -19
- data/manual/bounding_box/stretchy.rb +18 -20
- data/manual/contents.rb +35 -0
- data/manual/cover.rb +43 -0
- data/manual/document_and_page_options/background.rb +16 -14
- data/manual/document_and_page_options/document_and_page_options.rb +26 -23
- data/manual/document_and_page_options/metadata.rb +21 -19
- data/manual/document_and_page_options/page_margins.rb +20 -22
- data/manual/document_and_page_options/page_size.rb +15 -15
- data/manual/document_and_page_options/print_scaling.rb +23 -0
- data/manual/example_helper.rb +5 -408
- data/manual/graphics/blend_mode.rb +52 -0
- data/manual/graphics/circle_and_ellipse.rb +8 -9
- data/manual/graphics/color.rb +11 -13
- data/manual/graphics/common_lines.rb +13 -12
- data/manual/graphics/fill_and_stroke.rb +10 -11
- data/manual/graphics/fill_rules.rb +13 -12
- data/manual/graphics/gradients.rb +28 -22
- data/manual/graphics/graphics.rb +52 -46
- data/manual/graphics/helper.rb +20 -10
- data/manual/graphics/line_width.rb +13 -12
- data/manual/graphics/lines_and_curves.rb +13 -14
- data/manual/graphics/polygon.rb +10 -12
- data/manual/graphics/rectangle.rb +7 -8
- data/manual/graphics/rotate.rb +9 -12
- data/manual/graphics/scale.rb +19 -18
- data/manual/graphics/soft_masks.rb +5 -7
- data/manual/graphics/stroke_cap.rb +10 -11
- data/manual/graphics/stroke_dash.rb +16 -17
- data/manual/graphics/stroke_join.rb +10 -11
- data/manual/graphics/translate.rb +13 -13
- data/manual/graphics/transparency.rb +11 -13
- data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +23 -25
- data/manual/images/absolute_position.rb +9 -10
- data/manual/images/fit.rb +9 -10
- data/manual/images/horizontal.rb +13 -14
- data/manual/images/images.rb +31 -30
- data/manual/images/plain_image.rb +6 -7
- data/manual/images/scale.rb +12 -13
- data/manual/images/vertical.rb +19 -17
- data/manual/images/width_and_height.rb +13 -14
- data/manual/layout/boxes.rb +14 -15
- data/manual/layout/content.rb +12 -13
- data/manual/layout/layout.rb +19 -20
- data/manual/layout/simple_grid.rb +8 -9
- data/manual/outline/add_subsection_to.rb +26 -27
- data/manual/outline/insert_section_after.rb +19 -20
- data/manual/outline/outline.rb +23 -22
- data/manual/outline/sections_and_pages.rb +24 -25
- data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
- data/manual/repeatable_content/page_numbering.rb +20 -19
- data/manual/repeatable_content/repeatable_content.rb +26 -22
- data/manual/repeatable_content/repeater.rb +18 -19
- data/manual/repeatable_content/stamp.rb +18 -19
- data/manual/security/encryption.rb +8 -11
- data/manual/security/permissions.rb +20 -15
- data/manual/security/security.rb +20 -20
- data/manual/table.rb +16 -0
- data/manual/text/alignment.rb +17 -18
- data/manual/text/color.rb +13 -13
- data/manual/text/column_box.rb +10 -12
- data/manual/text/fallback_fonts.rb +29 -25
- data/manual/text/font.rb +17 -18
- data/manual/text/font_size.rb +21 -22
- data/manual/text/font_style.rb +12 -10
- data/manual/text/formatted_callbacks.rb +36 -26
- data/manual/text/formatted_text.rb +41 -34
- data/manual/text/free_flowing_text.rb +28 -29
- data/manual/text/inline.rb +23 -26
- data/manual/text/kerning_and_character_spacing.rb +20 -21
- data/manual/text/leading.rb +10 -11
- data/manual/text/line_wrapping.rb +40 -21
- data/manual/text/paragraph_indentation.rb +17 -12
- data/manual/text/positioned_text.rb +19 -20
- data/manual/text/registering_families.rb +33 -30
- data/manual/text/rendering_and_color.rb +11 -12
- data/manual/text/right_to_left_text.rb +31 -20
- data/manual/text/rotation.rb +36 -27
- data/manual/text/single_usage.rb +13 -14
- data/manual/text/text.rb +62 -62
- data/manual/text/text_box_excess.rb +22 -19
- data/manual/text/text_box_extensions.rb +21 -18
- data/manual/text/text_box_overflow.rb +28 -21
- data/manual/text/utf8.rb +16 -17
- data/manual/text/win_ansi_charset.rb +29 -26
- data/prawn.gemspec +45 -43
- data/spec/extensions/encoding_helpers.rb +4 -3
- data/spec/prawn/document/bounding_box_spec.rb +550 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +44 -0
- data/spec/prawn/document_spec.rb +805 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +544 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +872 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/prawn/image_handler_spec.rb +53 -0
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +229 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +512 -0
- data/spec/prawn/repeater_spec.rb +166 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +173 -0
- data/spec/prawn/text/box_spec.rb +1110 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +849 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +150 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/prawn/transformation_stack_spec.rb +66 -0
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +22 -21
- data.tar.gz.sig +0 -0
- metadata +168 -307
- metadata.gz.sig +0 -0
- data/README.md +0 -109
- data/data/encodings/win_ansi.txt +0 -29
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.dat +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/barcode_issue.png +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.dat +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/lib/pdf/core/annotations.rb +0 -60
- data/lib/pdf/core/byte_string.rb +0 -9
- data/lib/pdf/core/destinations.rb +0 -90
- data/lib/pdf/core/document_state.rb +0 -78
- data/lib/pdf/core/filter_list.rb +0 -51
- data/lib/pdf/core/filters.rb +0 -36
- data/lib/pdf/core/graphics_state.rb +0 -68
- data/lib/pdf/core/literal_string.rb +0 -16
- data/lib/pdf/core/name_tree.rb +0 -177
- data/lib/pdf/core/object_store.rb +0 -320
- data/lib/pdf/core/outline.rb +0 -315
- data/lib/pdf/core/page.rb +0 -212
- data/lib/pdf/core/page_geometry.rb +0 -126
- data/lib/pdf/core/pdf_object.rb +0 -124
- data/lib/pdf/core/reference.rb +0 -103
- data/lib/pdf/core/stream.rb +0 -98
- data/lib/pdf/core/text.rb +0 -275
- data/lib/pdf/core.rb +0 -35
- data/lib/prawn/compatibility.rb +0 -91
- data/lib/prawn/document/graphics_state.rb +0 -73
- data/lib/prawn/document/snapshot.rb +0 -89
- data/lib/prawn/font/afm.rb +0 -203
- data/lib/prawn/layout.rb +0 -20
- data/lib/prawn/table/cell/image.rb +0 -70
- data/lib/prawn/table/cell/in_table.rb +0 -27
- data/lib/prawn/table/cell/span_dummy.rb +0 -92
- data/lib/prawn/table/cell/subtable.rb +0 -65
- data/lib/prawn/table/cell/text.rb +0 -153
- data/lib/prawn/table/cell.rb +0 -770
- data/lib/prawn/table/cells.rb +0 -295
- data/lib/prawn/table.rb +0 -643
- data/manual/example_file.rb +0 -116
- data/manual/example_package.rb +0 -53
- data/manual/example_section.rb +0 -46
- data/manual/manual/cover.rb +0 -35
- data/manual/manual/foreword.rb +0 -85
- data/manual/manual/manual.rb +0 -35
- data/manual/syntax_highlight.rb +0 -52
- data/manual/table/basic_block.rb +0 -53
- data/manual/table/before_rendering_page.rb +0 -26
- data/manual/table/cell_border_lines.rb +0 -24
- data/manual/table/cell_borders_and_bg.rb +0 -31
- data/manual/table/cell_dimensions.rb +0 -30
- data/manual/table/cell_text.rb +0 -38
- data/manual/table/column_widths.rb +0 -30
- data/manual/table/content_and_subtables.rb +0 -39
- data/manual/table/creation.rb +0 -27
- data/manual/table/filtering.rb +0 -36
- data/manual/table/flow_and_header.rb +0 -17
- data/manual/table/image_cells.rb +0 -33
- data/manual/table/position.rb +0 -29
- data/manual/table/row_colors.rb +0 -20
- data/manual/table/span.rb +0 -30
- data/manual/table/style.rb +0 -22
- data/manual/table/table.rb +0 -52
- data/manual/table/width.rb +0 -27
- data/manual/templates/full_template.rb +0 -25
- data/manual/templates/page_template.rb +0 -48
- data/manual/templates/templates.rb +0 -27
- data/manual/text/group.rb +0 -29
- data/spec/acceptance/png.rb +0 -23
- data/spec/annotations_spec.rb +0 -74
- data/spec/bounding_box_spec.rb +0 -493
- data/spec/cell_spec.rb +0 -628
- data/spec/column_box_spec.rb +0 -33
- data/spec/destinations_spec.rb +0 -15
- data/spec/document_spec.rb +0 -761
- data/spec/extensions/mocha.rb +0 -44
- data/spec/filters_spec.rb +0 -34
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -464
- data/spec/formatted_text_arranger_spec.rb +0 -421
- data/spec/formatted_text_box_spec.rb +0 -650
- data/spec/formatted_text_fragment_spec.rb +0 -298
- data/spec/graphics_spec.rb +0 -651
- data/spec/grid_spec.rb +0 -85
- data/spec/image_handler_spec.rb +0 -42
- data/spec/images_spec.rb +0 -157
- data/spec/inline_formatted_text_parser_spec.rb +0 -564
- data/spec/jpg_spec.rb +0 -25
- data/spec/line_wrap_spec.rb +0 -333
- data/spec/measurement_units_spec.rb +0 -23
- data/spec/name_tree_spec.rb +0 -112
- data/spec/object_store_spec.rb +0 -170
- data/spec/outline_spec.rb +0 -448
- data/spec/pdf_object_spec.rb +0 -172
- data/spec/png_spec.rb +0 -240
- data/spec/reference_spec.rb +0 -82
- data/spec/repeater_spec.rb +0 -158
- data/spec/security_spec.rb +0 -158
- data/spec/snapshot_spec.rb +0 -186
- data/spec/soft_mask_spec.rb +0 -117
- data/spec/span_spec.rb +0 -44
- data/spec/stamp_spec.rb +0 -158
- data/spec/stream_spec.rb +0 -58
- data/spec/stroke_styles_spec.rb +0 -211
- data/spec/table/span_dummy_spec.rb +0 -17
- data/spec/table_spec.rb +0 -1355
- data/spec/template_spec.rb +0 -351
- data/spec/text_at_spec.rb +0 -130
- data/spec/text_box_spec.rb +0 -1030
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -425
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -89
data/lib/prawn/security.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# encryption.rb : Implements encrypted PDF and access permissions.
|
4
4
|
#
|
5
5
|
# Copyright August 2008, Brad Ediger. All Rights Reserved.
|
@@ -7,17 +7,15 @@
|
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
|
9
9
|
require 'digest/md5'
|
10
|
-
require 'rc4'
|
11
10
|
|
12
|
-
require_relative '
|
11
|
+
require_relative 'security/arcfour'
|
13
12
|
|
14
13
|
module Prawn
|
15
14
|
class Document
|
16
|
-
|
17
15
|
# Implements PDF encryption (password protection and permissions) as
|
18
16
|
# specified in the PDF Reference, version 1.3, section 3.5 "Encryption".
|
19
17
|
module Security
|
20
|
-
|
18
|
+
# @group Experimental API
|
21
19
|
|
22
20
|
# Encrypts the document, to protect confidential data or control
|
23
21
|
# modifications to the document. The encryption algorithm used is
|
@@ -87,15 +85,15 @@ module Prawn
|
|
87
85
|
# not a limitation of Prawn, but is rather a built-in limitation of the
|
88
86
|
# PDF format.
|
89
87
|
#
|
90
|
-
def encrypt_document(options={})
|
91
|
-
Prawn.verify_options [
|
88
|
+
def encrypt_document(options = {})
|
89
|
+
Prawn.verify_options %i[user_password owner_password permissions],
|
92
90
|
options
|
93
|
-
@user_password = options.delete(:user_password) ||
|
91
|
+
@user_password = options.delete(:user_password) || ''
|
94
92
|
|
95
93
|
@owner_password = options.delete(:owner_password) || @user_password
|
96
94
|
if @owner_password == :random
|
97
95
|
# Generate a completely ridiculous password
|
98
|
-
@owner_password = (1..32).map{ rand(256) }.pack(
|
96
|
+
@owner_password = (1..32).map { rand(256) }.pack('c*')
|
99
97
|
end
|
100
98
|
|
101
99
|
self.permissions = options.delete(:permissions) || {}
|
@@ -111,45 +109,54 @@ module Prawn
|
|
111
109
|
# See Algorithm 3.1.
|
112
110
|
def self.encrypt_string(str, key, id, gen)
|
113
111
|
# Convert ID and Gen number into little-endian truncated byte strings
|
114
|
-
id = [id].pack('V')[0,3]
|
115
|
-
gen = [gen].pack('V')[0,2]
|
112
|
+
id = [id].pack('V')[0, 3]
|
113
|
+
gen = [gen].pack('V')[0, 2]
|
116
114
|
extended_key = "#{key}#{id}#{gen}"
|
117
115
|
|
118
116
|
# Compute the RC4 key from the extended key and perform the encryption
|
119
117
|
rc4_key = Digest::MD5.digest(extended_key)[0, 10]
|
120
|
-
|
118
|
+
Arcfour.new(rc4_key).encrypt(str)
|
121
119
|
end
|
122
120
|
|
123
121
|
private
|
124
122
|
|
125
123
|
# Provides the values for the trailer encryption dictionary.
|
126
124
|
def encryption_dictionary
|
127
|
-
{
|
128
|
-
:
|
129
|
-
:
|
130
|
-
:
|
131
|
-
:
|
132
|
-
:
|
125
|
+
{
|
126
|
+
Filter: :Standard, # default PDF security handler
|
127
|
+
V: 1, # "Algorithm 3.1", PDF reference 1.3
|
128
|
+
R: 2, # Revision 2 of the algorithm
|
129
|
+
O: PDF::Core::ByteString.new(owner_password_hash),
|
130
|
+
U: PDF::Core::ByteString.new(user_password_hash),
|
131
|
+
P: permissions_value
|
132
|
+
}
|
133
133
|
end
|
134
134
|
|
135
135
|
# Flags in the permissions word, numbered as LSB = 1
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
136
|
+
PERMISSIONS_BITS = {
|
137
|
+
print_document: 3,
|
138
|
+
modify_contents: 4,
|
139
|
+
copy_contents: 5,
|
140
|
+
modify_annotations: 6
|
141
|
+
}.freeze
|
142
|
+
private_constant :PERMISSIONS_BITS
|
143
|
+
|
144
|
+
FULL_PERMISSIONS = 0b1111_1111_1111_1111_1111_1111_1111_1111
|
145
|
+
private_constant :FULL_PERMISSIONS
|
146
|
+
|
147
|
+
def permissions=(perms = {})
|
148
|
+
@permissions ||= FULL_PERMISSIONS
|
145
149
|
perms.each do |key, value|
|
146
|
-
unless
|
147
|
-
raise
|
148
|
-
|
150
|
+
unless PERMISSIONS_BITS[key]
|
151
|
+
raise(
|
152
|
+
ArgumentError,
|
153
|
+
"Unknown permission :#{key}. Valid options: " +
|
154
|
+
PERMISSIONS_BITS.keys.map(&:inspect).join(', ')
|
155
|
+
)
|
149
156
|
end
|
150
157
|
|
151
158
|
# 0-based bit number, from LSB
|
152
|
-
bit_position =
|
159
|
+
bit_position = PERMISSIONS_BITS[key] - 1
|
153
160
|
|
154
161
|
if value # set bit
|
155
162
|
@permissions |= (1 << bit_position)
|
@@ -160,122 +167,137 @@ module Prawn
|
|
160
167
|
end
|
161
168
|
|
162
169
|
def permissions_value
|
163
|
-
@permissions ||
|
170
|
+
@permissions || FULL_PERMISSIONS
|
164
171
|
end
|
165
172
|
|
166
|
-
|
167
|
-
|
168
|
-
|
173
|
+
PASSWORD_PADDING =
|
174
|
+
'28BF4E5E4E758A4164004E56FFFA01082E2E00B6D0683E802F0CA9FE6453697A'
|
175
|
+
.scan(/../).map { |x| x.to_i(16) }.pack('c*')
|
169
176
|
|
170
177
|
# Pads or truncates a password to 32 bytes as per Alg 3.2.
|
171
178
|
def pad_password(password)
|
172
179
|
password = password[0, 32]
|
173
|
-
password +
|
180
|
+
password + PASSWORD_PADDING[0, 32 - password.length]
|
174
181
|
end
|
175
182
|
|
176
183
|
def user_encryption_key
|
177
|
-
@user_encryption_key ||=
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
+
@user_encryption_key ||=
|
185
|
+
begin
|
186
|
+
md5 = Digest::MD5.new
|
187
|
+
md5 << pad_password(@user_password)
|
188
|
+
md5 << owner_password_hash
|
189
|
+
md5 << [permissions_value].pack('V')
|
190
|
+
md5.digest[0, 5]
|
191
|
+
end
|
184
192
|
end
|
185
193
|
|
186
194
|
# The O (owner) value in the encryption dictionary. Algorithm 3.3.
|
187
195
|
def owner_password_hash
|
188
|
-
@owner_password_hash ||=
|
189
|
-
|
190
|
-
|
191
|
-
|
196
|
+
@owner_password_hash ||=
|
197
|
+
begin
|
198
|
+
key = Digest::MD5.digest(pad_password(@owner_password))[0, 5]
|
199
|
+
Arcfour.new(key).encrypt(pad_password(@user_password))
|
200
|
+
end
|
192
201
|
end
|
193
202
|
|
194
203
|
# The U (user) value in the encryption dictionary. Algorithm 3.4.
|
195
204
|
def user_password_hash
|
196
|
-
|
205
|
+
Arcfour.new(user_encryption_key).encrypt(PASSWORD_PADDING)
|
197
206
|
end
|
198
|
-
|
199
207
|
end
|
200
|
-
|
201
208
|
end
|
202
209
|
end
|
203
210
|
|
204
|
-
|
211
|
+
# @private
|
212
|
+
module PDF
|
205
213
|
module Core
|
206
214
|
module_function
|
207
215
|
|
208
|
-
# Like
|
216
|
+
# Like pdf_object, but returns an encrypted result if required.
|
209
217
|
# For direct objects, requires the object identifier and generation number
|
210
218
|
# from the indirect object referencing obj.
|
211
|
-
|
219
|
+
#
|
220
|
+
# @private
|
221
|
+
def encrypted_pdf_object(obj, key, id, gen, in_content_stream = false)
|
212
222
|
case obj
|
213
223
|
when Array
|
214
|
-
|
215
|
-
|
216
|
-
|
224
|
+
array_content = obj.map do |e|
|
225
|
+
encrypted_pdf_object(e, key, id, gen, in_content_stream)
|
226
|
+
end.join(' ')
|
227
|
+
"[#{array_content}]"
|
217
228
|
when LiteralString
|
218
|
-
obj =
|
229
|
+
obj =
|
230
|
+
ByteString.new(
|
231
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
232
|
+
).gsub(/[\\\n()]/) { |m| "\\#{m}" }
|
219
233
|
"(#{obj})"
|
220
234
|
when Time
|
221
|
-
obj = obj.strftime(
|
222
|
-
obj =
|
235
|
+
obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
|
236
|
+
obj =
|
237
|
+
ByteString.new(
|
238
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
239
|
+
).gsub(/[\\\n()]/) { |m| "\\#{m}" }
|
223
240
|
"(#{obj})"
|
224
241
|
when String
|
225
|
-
|
242
|
+
pdf_object(
|
226
243
|
ByteString.new(
|
227
|
-
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
228
|
-
|
244
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
245
|
+
),
|
246
|
+
in_content_stream
|
247
|
+
)
|
229
248
|
when ::Hash
|
230
|
-
|
231
|
-
|
232
|
-
unless String === k || Symbol === k
|
249
|
+
hash_content = obj.map do |k, v|
|
250
|
+
unless k.is_a?(String) || k.is_a?(Symbol)
|
233
251
|
raise PDF::Core::Errors::FailedObjectConversion,
|
234
|
-
|
252
|
+
'A PDF Dictionary must be keyed by names'
|
235
253
|
end
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
output << ">>"
|
254
|
+
"#{pdf_object(k.to_sym, in_content_stream)} #{encrypted_pdf_object(v, key, id, gen, in_content_stream)}\n"
|
255
|
+
end.join('')
|
256
|
+
"<< #{hash_content}>>"
|
240
257
|
when NameTree::Value
|
241
|
-
|
242
|
-
EncryptedPdfObject(obj.value, key, id, gen, in_content_stream)
|
258
|
+
"#{pdf_object(obj.name)} #{encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)}"
|
243
259
|
when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
|
244
|
-
|
245
|
-
else # delegate back to
|
246
|
-
|
260
|
+
encrypted_pdf_object(obj.to_hash, key, id, gen, in_content_stream)
|
261
|
+
else # delegate back to pdf_object
|
262
|
+
pdf_object(obj, in_content_stream)
|
247
263
|
end
|
248
264
|
end
|
249
265
|
|
250
|
-
|
266
|
+
# @private
|
251
267
|
class Stream
|
252
268
|
def encrypted_object(key, id, gen)
|
253
269
|
if filtered_stream
|
254
|
-
"stream\n#{
|
270
|
+
"stream\n#{
|
271
|
+
Prawn::Document::Security.encrypt_string(
|
272
|
+
filtered_stream, key, id, gen
|
273
|
+
)
|
274
|
+
}\nendstream\n"
|
255
275
|
else
|
256
276
|
''
|
257
277
|
end
|
258
278
|
end
|
259
279
|
end
|
260
280
|
|
281
|
+
# @private
|
261
282
|
class Reference
|
262
|
-
|
263
283
|
# Returns the object definition for the object this references, keyed from
|
264
284
|
# +key+.
|
265
285
|
def encrypted_object(key)
|
266
|
-
@on_encode
|
286
|
+
@on_encode&.call(self)
|
267
287
|
|
268
|
-
output = "#{@identifier} #{gen} obj\n"
|
269
|
-
|
270
|
-
output <<
|
271
|
-
|
288
|
+
output = +"#{@identifier} #{gen} obj\n"
|
289
|
+
if @stream.empty?
|
290
|
+
output <<
|
291
|
+
PDF::Core.encrypted_pdf_object(data, key, @identifier, gen) << "\n"
|
272
292
|
else
|
273
|
-
output << PDF::Core
|
293
|
+
output << PDF::Core.encrypted_pdf_object(
|
294
|
+
data.merge(@stream.data), key, @identifier, gen
|
295
|
+
) << "\n" <<
|
296
|
+
@stream.encrypted_object(key, @identifier, gen)
|
274
297
|
end
|
275
298
|
|
276
299
|
output << "endobj\n"
|
277
300
|
end
|
278
|
-
|
279
301
|
end
|
280
302
|
end
|
281
303
|
end
|
data/lib/prawn/soft_mask.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# soft_mask.rb : Implements soft-masking
|
4
4
|
#
|
5
5
|
# Copyright September 2012, Alexander Mankuta. All Rights Reserved.
|
@@ -8,9 +8,8 @@
|
|
8
8
|
#
|
9
9
|
|
10
10
|
module Prawn
|
11
|
-
|
12
11
|
# The Prawn::SoftMask module is used to create arbitrary transparency in
|
13
|
-
# document. Using a soft mask allows
|
12
|
+
# document. Using a soft mask allows creating more visually rich documents.
|
14
13
|
#
|
15
14
|
# You must group soft mask and graphics it's applied to under
|
16
15
|
# save_graphics_state because soft mask is a part of graphic state in PDF.
|
@@ -26,62 +25,62 @@ module Prawn
|
|
26
25
|
# end
|
27
26
|
#
|
28
27
|
module SoftMask
|
28
|
+
# @group Stable API
|
29
|
+
|
29
30
|
def soft_mask(&block)
|
30
|
-
min_version(1.4)
|
31
|
+
renderer.min_version(1.4)
|
31
32
|
|
32
|
-
group_attrs = ref!(
|
33
|
-
:
|
34
|
-
:
|
35
|
-
:
|
36
|
-
:
|
37
|
-
:
|
38
|
-
|
33
|
+
group_attrs = ref!(
|
34
|
+
Type: :Group,
|
35
|
+
S: :Transparency,
|
36
|
+
CS: :DeviceRGB,
|
37
|
+
I: false,
|
38
|
+
K: false
|
39
|
+
)
|
39
40
|
|
40
|
-
group = ref!(
|
41
|
-
:
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
|
41
|
+
group = ref!(
|
42
|
+
Type: :XObject,
|
43
|
+
Subtype: :Form,
|
44
|
+
BBox: state.page.dimensions,
|
45
|
+
Group: group_attrs
|
46
|
+
)
|
46
47
|
|
47
48
|
state.page.stamp_stream(group, &block)
|
48
49
|
|
49
|
-
mask = ref!(
|
50
|
-
:
|
51
|
-
:
|
52
|
-
:
|
53
|
-
|
50
|
+
mask = ref!(
|
51
|
+
Type: :Mask,
|
52
|
+
S: :Luminosity,
|
53
|
+
G: group
|
54
|
+
)
|
54
55
|
|
55
|
-
g_state = ref!(
|
56
|
-
:
|
57
|
-
:
|
56
|
+
g_state = ref!(
|
57
|
+
Type: :ExtGState,
|
58
|
+
SMask: mask,
|
58
59
|
|
59
|
-
:
|
60
|
-
:
|
61
|
-
:
|
62
|
-
:
|
63
|
-
:
|
64
|
-
:
|
65
|
-
|
60
|
+
AIS: false,
|
61
|
+
BM: :Normal,
|
62
|
+
OP: false,
|
63
|
+
op: false,
|
64
|
+
OPM: 1,
|
65
|
+
SA: true
|
66
|
+
)
|
66
67
|
|
67
68
|
registry_key = {
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
69
|
+
bbox: state.page.dimensions,
|
70
|
+
mask: [group.stream.filters.normalized, group.stream.filtered_stream],
|
71
|
+
page: state.page_count
|
71
72
|
}.hash
|
72
73
|
|
73
74
|
if soft_mask_registry[registry_key]
|
74
|
-
|
75
|
-
|
76
|
-
add_content "/#{soft_mask_registry[registry_key]} gs"
|
75
|
+
renderer.add_content "/#{soft_mask_registry[registry_key]} gs"
|
77
76
|
else
|
78
77
|
masks = page.resources[:ExtGState] ||= {}
|
79
|
-
id = masks.empty? ? 'GS1' : masks.keys.
|
78
|
+
id = masks.empty? ? 'GS1' : masks.keys.max.succ
|
80
79
|
masks[id] = g_state
|
81
80
|
|
82
81
|
soft_mask_registry[registry_key] = id
|
83
82
|
|
84
|
-
add_content "/#{id} gs"
|
83
|
+
renderer.add_content "/#{id} gs"
|
85
84
|
end
|
86
85
|
end
|
87
86
|
|
data/lib/prawn/stamp.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# stamp.rb : Implements a repeatable stamp
|
4
4
|
#
|
5
5
|
# Copyright October 2009, Daniel Nelson. All Rights Reserved.
|
6
6
|
#
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
#
|
9
|
-
|
10
9
|
module Prawn
|
11
|
-
|
12
10
|
# The Prawn::Stamp module is used to create content that will be
|
13
11
|
# included multiple times in a document. Using a stamp has three
|
14
12
|
# advantages over creating content anew each time it is placed on
|
@@ -27,6 +25,7 @@ module Prawn
|
|
27
25
|
# pdf.stamp("my_stamp")
|
28
26
|
#
|
29
27
|
module Stamp
|
28
|
+
# @group Stable API
|
30
29
|
|
31
30
|
# Renders the stamp named <tt>name</tt> to the page
|
32
31
|
# raises <tt>Prawn::Errors::InvalidName</tt> if name.empty?
|
@@ -42,7 +41,8 @@ module Prawn
|
|
42
41
|
#
|
43
42
|
def stamp(name)
|
44
43
|
dictionary_name, dictionary = stamp_dictionary(name)
|
45
|
-
add_content "/#{dictionary_name} Do"
|
44
|
+
renderer.add_content "/#{dictionary_name} Do"
|
45
|
+
update_annotation_references dictionary.data[:Annots]
|
46
46
|
state.page.xobjects.merge!(dictionary_name => dictionary)
|
47
47
|
end
|
48
48
|
|
@@ -107,21 +107,39 @@ module Prawn
|
|
107
107
|
def create_stamp_dictionary(name)
|
108
108
|
raise Prawn::Errors::InvalidName if name.empty?
|
109
109
|
raise Prawn::Errors::NameTaken unless stamp_dictionary_registry[name].nil?
|
110
|
+
|
110
111
|
# BBox origin is the lower left margin of the page, so we need
|
111
112
|
# it to be the full dimension of the page, or else things that
|
112
113
|
# should appear near the top or right margin are invisible
|
113
|
-
dictionary = ref!(
|
114
|
-
|
115
|
-
|
116
|
-
|
114
|
+
dictionary = ref!(
|
115
|
+
Type: :XObject,
|
116
|
+
Subtype: :Form,
|
117
|
+
BBox: [
|
118
|
+
0, 0,
|
119
|
+
state.page.dimensions[2], state.page.dimensions[3]
|
120
|
+
]
|
121
|
+
)
|
117
122
|
|
118
123
|
dictionary_name = "Stamp#{next_stamp_dictionary_id}"
|
119
124
|
|
120
|
-
stamp_dictionary_registry[name] = {
|
121
|
-
|
125
|
+
stamp_dictionary_registry[name] = {
|
126
|
+
stamp_dictionary_name: dictionary_name,
|
127
|
+
stamp_dictionary: dictionary
|
128
|
+
}
|
122
129
|
dictionary
|
123
130
|
end
|
124
131
|
|
132
|
+
# Referencing annotations from a stamp XObject doesn't result
|
133
|
+
# in a working link. Instead, the references must be appended
|
134
|
+
# to the /Annot dictionary of the object that contains the
|
135
|
+
# call to the stamp object.
|
136
|
+
def update_annotation_references(annots)
|
137
|
+
if annots&.any?
|
138
|
+
state.page.dictionary.data[:Annots] ||= []
|
139
|
+
state.page.dictionary.data[:Annots] |= annots
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
125
143
|
def freeze_stamp_graphics
|
126
144
|
update_colors
|
127
145
|
write_line_width
|
@@ -129,6 +147,5 @@ module Prawn
|
|
129
147
|
write_stroke_join_style
|
130
148
|
write_stroke_dash
|
131
149
|
end
|
132
|
-
|
133
150
|
end
|
134
151
|
end
|
data/lib/prawn/text/box.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# text/rectangle.rb : Implements text boxes
|
4
4
|
#
|
@@ -7,10 +7,11 @@
|
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
#
|
9
9
|
|
10
|
-
require_relative
|
10
|
+
require_relative 'formatted/box'
|
11
11
|
|
12
12
|
module Prawn
|
13
13
|
module Text
|
14
|
+
# @group Stable API
|
14
15
|
|
15
16
|
# Draws the requested text into a box. When the text overflows
|
16
17
|
# the rectangle, you shrink to fit, or truncate the text. Text
|
@@ -39,6 +40,8 @@ module Prawn
|
|
39
40
|
# <tt>:character_spacing</tt>:: <tt>number</tt>. The amount of space to add
|
40
41
|
# to or remove from the default character
|
41
42
|
# spacing. [0]
|
43
|
+
# <tt>:disable_wrap_by_char</tt>:: <tt>boolean</tt> Whether
|
44
|
+
# or not to prevent mid-word breaks when text does not fit in box. [false]
|
42
45
|
# <tt>:mode</tt>:: <tt>symbol</tt>. The text rendering mode. See
|
43
46
|
# documentation for Prawn::Document#text_rendering_mode
|
44
47
|
# for a list of valid options. [:fill]
|
@@ -49,7 +52,8 @@ module Prawn
|
|
49
52
|
# <tt>[x, y]</tt>. The upper left corner of the box
|
50
53
|
# [@document.bounds.left, @document.bounds.top]
|
51
54
|
# <tt>:width</tt>::
|
52
|
-
# <tt>number</tt>. The width of the box
|
55
|
+
# <tt>number</tt>. The width of the box
|
56
|
+
# [@document.bounds.right - @at[0]]
|
53
57
|
# <tt>:height</tt>::
|
54
58
|
# <tt>number</tt>. The height of the box [default_height()]
|
55
59
|
# <tt>:direction</tt>::
|
@@ -57,7 +61,7 @@ module Prawn
|
|
57
61
|
# or right-to-left) [value of document.text_direction]
|
58
62
|
# <tt>:fallback_fonts</tt>::
|
59
63
|
# An array of font names. Each name must be the name of an AFM font or
|
60
|
-
# the name that was used to register a family of
|
64
|
+
# the name that was used to register a family of external fonts (see
|
61
65
|
# Prawn::Document#font_families). If present, then each glyph will be
|
62
66
|
# rendered using the first font that includes the glyph, starting with
|
63
67
|
# the current font and then moving through :fallback_fonts from
|
@@ -69,7 +73,6 @@ module Prawn
|
|
69
73
|
# <tt>:valign</tt>::
|
70
74
|
# <tt>:top</tt>, <tt>:center</tt>, or <tt>:bottom</tt>. Vertical
|
71
75
|
# alignment within the bounding box [:top]
|
72
|
-
#
|
73
76
|
# <tt>:rotate</tt>::
|
74
77
|
# <tt>number</tt>. The angle to rotate the text
|
75
78
|
# <tt>:rotate_around</tt>::
|
@@ -80,9 +83,8 @@ module Prawn
|
|
80
83
|
# <tt>number</tt>. Additional space between lines [value of
|
81
84
|
# document.default_leading]
|
82
85
|
# <tt>:single_line</tt>::
|
83
|
-
# <tt>boolean</tt>. If true, then only the first line will be drawn
|
84
|
-
#
|
85
|
-
# <tt>boolean</tt> [false]
|
86
|
+
# <tt>boolean</tt>. If true, then only the first line will be drawn
|
87
|
+
# [false]
|
86
88
|
# <tt>:overflow</tt>::
|
87
89
|
# <tt>:truncate</tt>, <tt>:shrink_to_fit</tt>, or <tt>:expand</tt>
|
88
90
|
# This controls the behavior when the amount of text
|
@@ -96,31 +98,30 @@ module Prawn
|
|
96
98
|
#
|
97
99
|
# Returns any text that did not print under the current settings.
|
98
100
|
#
|
99
|
-
# NOTE: if an AFM font is used, then the returned text is encoded in
|
100
|
-
# WinAnsi. Subsequent calls to text_box that pass this returned text back
|
101
|
-
# into text box must include a :skip_encoding => true option. This is
|
102
|
-
# unnecessary when using TTF fonts because those operate on UTF-8 encoding.
|
103
|
-
#
|
104
101
|
# == Exceptions
|
105
102
|
#
|
106
|
-
# Raises <tt>Prawn::
|
103
|
+
# Raises <tt>Prawn::Errors::CannotFit</tt> if not wide enough to print
|
107
104
|
# any text
|
108
105
|
#
|
109
|
-
def text_box(string, options={})
|
106
|
+
def text_box(string, options = {})
|
110
107
|
options = options.dup
|
111
108
|
options[:document] = self
|
112
109
|
|
113
|
-
box =
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
110
|
+
box =
|
111
|
+
if options[:inline_format]
|
112
|
+
p = options.delete(:inline_format)
|
113
|
+
p = [] unless p.is_a?(Array)
|
114
|
+
array = text_formatter.format(string, *p)
|
115
|
+
Text::Formatted::Box.new(array, options)
|
116
|
+
else
|
117
|
+
Text::Box.new(string, options)
|
118
|
+
end
|
120
119
|
|
121
120
|
box.render
|
122
121
|
end
|
123
122
|
|
123
|
+
# @group Experimental API
|
124
|
+
|
124
125
|
# Generally, one would use the Prawn::Text#text_box convenience
|
125
126
|
# method. However, using Text::Box.new in conjunction with
|
126
127
|
# #render(:dry_run=> true) enables one to do look-ahead calculations prior
|
@@ -128,17 +129,14 @@ module Prawn
|
|
128
129
|
# consumed by the printed text
|
129
130
|
#
|
130
131
|
class Box < Prawn::Text::Formatted::Box
|
131
|
-
|
132
|
-
|
133
|
-
super([{ :text => string }], options)
|
132
|
+
def initialize(string, options = {})
|
133
|
+
super([{ text: string }], options)
|
134
134
|
end
|
135
135
|
|
136
|
-
def render(flags={})
|
136
|
+
def render(flags = {})
|
137
137
|
leftover = super(flags)
|
138
|
-
leftover.
|
138
|
+
leftover.map { |hash| hash[:text] }.join
|
139
139
|
end
|
140
|
-
|
141
140
|
end
|
142
|
-
|
143
141
|
end
|
144
142
|
end
|