prawn 2.0.2 → 2.3.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.tar.gz.sig +0 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +20 -23
- data/lib/prawn.rb +37 -49
- data/lib/prawn/document.rb +181 -133
- data/lib/prawn/document/bounding_box.rb +41 -29
- data/lib/prawn/document/column_box.rb +7 -7
- data/lib/prawn/document/internals.rb +18 -8
- data/lib/prawn/document/span.rb +21 -16
- data/lib/prawn/encoding.rb +69 -68
- data/lib/prawn/errors.rb +12 -7
- data/lib/prawn/font.rb +115 -69
- data/lib/prawn/font_metric_cache.rb +14 -8
- data/lib/prawn/{font → fonts}/afm.rb +102 -68
- data/lib/prawn/{font → fonts}/dfont.rb +5 -11
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +87 -68
- data/lib/prawn/graphics.rb +120 -80
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +3 -3
- data/lib/prawn/graphics/color.rb +27 -25
- data/lib/prawn/graphics/dash.rb +23 -11
- data/lib/prawn/graphics/join_style.rb +9 -3
- data/lib/prawn/graphics/patterns.rb +197 -67
- data/lib/prawn/graphics/transformation.rb +17 -8
- data/lib/prawn/graphics/transparency.rb +17 -13
- data/lib/prawn/grid.rb +48 -47
- data/lib/prawn/image_handler.rb +5 -5
- data/lib/prawn/images.rb +39 -30
- data/lib/prawn/images/image.rb +2 -1
- data/lib/prawn/images/jpg.rb +28 -22
- data/lib/prawn/images/png.rb +107 -66
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +19 -15
- data/lib/prawn/outline.rb +97 -77
- data/lib/prawn/repeater.rb +14 -10
- data/lib/prawn/security.rb +81 -61
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/soft_mask.rb +26 -26
- data/lib/prawn/stamp.rb +20 -13
- data/lib/prawn/text.rb +68 -52
- data/lib/prawn/text/box.rb +11 -8
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text/formatted/arranger.rb +78 -49
- data/lib/prawn/text/formatted/box.rb +134 -100
- data/lib/prawn/text/formatted/fragment.rb +11 -14
- data/lib/prawn/text/formatted/line_wrap.rb +121 -63
- data/lib/prawn/text/formatted/parser.rb +139 -117
- data/lib/prawn/text/formatted/wrap.rb +43 -31
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +7 -22
- data/lib/prawn/version.rb +2 -2
- data/lib/prawn/view.rb +17 -7
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +31 -22
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +6 -7
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +22 -16
- data/manual/bounding_box/bounding_box.rb +29 -24
- data/manual/bounding_box/bounds.rb +11 -12
- data/manual/bounding_box/canvas.rb +4 -5
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +24 -17
- data/manual/bounding_box/russian_boxes.rb +14 -13
- data/manual/bounding_box/stretchy.rb +12 -13
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -28
- data/manual/document_and_page_options/background.rb +11 -13
- data/manual/document_and_page_options/document_and_page_options.rb +25 -20
- data/manual/document_and_page_options/metadata.rb +18 -16
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -12
- data/manual/document_and_page_options/print_scaling.rb +17 -15
- data/manual/example_helper.rb +5 -4
- data/manual/graphics/blend_mode.rb +52 -0
- data/manual/graphics/circle_and_ellipse.rb +4 -5
- data/manual/graphics/color.rb +7 -9
- data/manual/graphics/common_lines.rb +7 -8
- data/manual/graphics/fill_and_stroke.rb +4 -5
- data/manual/graphics/fill_rules.rb +9 -10
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +48 -39
- data/manual/graphics/helper.rb +12 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +7 -8
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -7
- data/manual/graphics/scale.rb +14 -15
- data/manual/graphics/soft_masks.rb +4 -5
- data/manual/graphics/stroke_cap.rb +6 -7
- data/manual/graphics/stroke_dash.rb +11 -12
- data/manual/graphics/stroke_join.rb +5 -6
- data/manual/graphics/translate.rb +9 -10
- data/manual/graphics/transparency.rb +7 -8
- data/manual/how_to_read_this_manual.rb +6 -6
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +9 -10
- data/manual/images/images.rb +28 -24
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +13 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +5 -6
- data/manual/layout/content.rb +7 -8
- data/manual/layout/layout.rb +18 -16
- data/manual/layout/simple_grid.rb +6 -7
- data/manual/outline/add_subsection_to.rb +20 -21
- data/manual/outline/insert_section_after.rb +15 -16
- data/manual/outline/outline.rb +21 -17
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +25 -19
- data/manual/repeatable_content/repeater.rb +14 -15
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +9 -10
- data/manual/security/permissions.rb +19 -14
- data/manual/security/security.rb +19 -16
- data/manual/table.rb +3 -3
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -11
- data/manual/text/column_box.rb +9 -10
- data/manual/text/fallback_fonts.rb +25 -21
- data/manual/text/font.rb +11 -12
- data/manual/text/font_size.rb +13 -14
- data/manual/text/font_style.rb +7 -8
- data/manual/text/formatted_callbacks.rb +25 -21
- data/manual/text/formatted_text.rb +33 -25
- data/manual/text/free_flowing_text.rb +20 -21
- data/manual/text/inline.rb +18 -19
- data/manual/text/kerning_and_character_spacing.rb +14 -15
- data/manual/text/leading.rb +7 -8
- data/manual/text/line_wrapping.rb +37 -18
- data/manual/text/paragraph_indentation.rb +13 -14
- data/manual/text/positioned_text.rb +15 -16
- data/manual/text/registering_families.rb +20 -21
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +26 -19
- data/manual/text/rotation.rb +28 -23
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +57 -52
- data/manual/text/text_box_excess.rb +20 -17
- data/manual/text/text_box_extensions.rb +18 -15
- data/manual/text/text_box_overflow.rb +18 -19
- data/manual/text/utf8.rb +11 -12
- data/manual/text/win_ansi_charset.rb +21 -19
- data/prawn.gemspec +45 -33
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +546 -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 +36 -0
- data/spec/prawn/document_spec.rb +802 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +542 -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 +837 -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 +224 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +412 -0
- data/spec/prawn/repeater_spec.rb +165 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +172 -0
- data/spec/prawn/text/box_spec.rb +1112 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +846 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +149 -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 +19 -23
- metadata +145 -185
- metadata.gz.sig +4 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +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/dice.alpha +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/fractal.jpg +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/license.md +0 -8
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pal_bk.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/spec/acceptance/png.rb +0 -24
- data/spec/annotations_spec.rb +0 -67
- data/spec/bounding_box_spec.rb +0 -501
- data/spec/column_box_spec.rb +0 -59
- data/spec/destinations_spec.rb +0 -13
- data/spec/document_spec.rb +0 -742
- data/spec/extensions/mocha.rb +0 -45
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -423
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -666
- data/spec/grid_spec.rb +0 -95
- data/spec/image_handler_spec.rb +0 -53
- data/spec/images_spec.rb +0 -167
- data/spec/inline_formatted_text_parser_spec.rb +0 -568
- data/spec/jpg_spec.rb +0 -23
- data/spec/line_wrap_spec.rb +0 -366
- data/spec/measurement_units_spec.rb +0 -22
- data/spec/outline_spec.rb +0 -409
- data/spec/png_spec.rb +0 -235
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -154
- data/spec/security_spec.rb +0 -151
- data/spec/soft_mask_spec.rb +0 -78
- data/spec/span_spec.rb +0 -43
- data/spec/stamp_spec.rb +0 -179
- data/spec/stroke_styles_spec.rb +0 -208
- data/spec/text_at_spec.rb +0 -142
- data/spec/text_box_spec.rb +0 -1038
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -549
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
- data/spec/view_spec.rb +0 -42
data/lib/prawn/measurements.rb
CHANGED
@@ -1,70 +1,74 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# measurements.rb: Conversions from other measurements to PDF points
|
3
4
|
#
|
4
5
|
# Copyright December 2008, Florian Witteler. All Rights Reserved.
|
5
6
|
#
|
7
|
+
|
8
|
+
# rubocop: disable Naming/MethodParameterName
|
6
9
|
module Prawn
|
7
10
|
# @group Stable API
|
8
11
|
|
9
12
|
module Measurements
|
10
13
|
# metric conversions
|
11
14
|
def cm2mm(cm)
|
12
|
-
|
15
|
+
cm * 10
|
13
16
|
end
|
14
17
|
|
15
18
|
def dm2mm(dm)
|
16
|
-
|
19
|
+
dm * 100
|
17
20
|
end
|
18
21
|
|
19
22
|
def m2mm(m)
|
20
|
-
|
23
|
+
m * 1000
|
21
24
|
end
|
22
25
|
|
23
26
|
# imperial conversions
|
24
27
|
# from http://en.wikipedia.org/wiki/Imperial_units
|
25
28
|
def ft2in(ft)
|
26
|
-
|
29
|
+
ft * 12
|
27
30
|
end
|
28
31
|
|
29
32
|
def yd2in(yd)
|
30
|
-
|
33
|
+
yd * 36
|
31
34
|
end
|
32
35
|
|
33
36
|
# PostscriptPoint-converisons
|
34
37
|
def pt2pt(pt)
|
35
|
-
|
38
|
+
pt
|
36
39
|
end
|
37
40
|
|
38
41
|
def in2pt(inch)
|
39
|
-
|
42
|
+
inch * 72
|
40
43
|
end
|
41
44
|
|
42
45
|
def ft2pt(ft)
|
43
|
-
|
46
|
+
in2pt(ft2in(ft))
|
44
47
|
end
|
45
48
|
|
46
49
|
def yd2pt(yd)
|
47
|
-
|
50
|
+
in2pt(yd2in(yd))
|
48
51
|
end
|
49
52
|
|
50
53
|
def mm2pt(mm)
|
51
|
-
|
54
|
+
mm * (72 / 25.4)
|
52
55
|
end
|
53
56
|
|
54
57
|
def cm2pt(cm)
|
55
|
-
|
58
|
+
mm2pt(cm2mm(cm))
|
56
59
|
end
|
57
60
|
|
58
61
|
def dm2pt(dm)
|
59
|
-
|
62
|
+
mm2pt(dm2mm(dm))
|
60
63
|
end
|
61
64
|
|
62
65
|
def m2pt(m)
|
63
|
-
|
66
|
+
mm2pt(m2mm(m))
|
64
67
|
end
|
65
68
|
|
66
69
|
def pt2mm(pt)
|
67
|
-
|
70
|
+
pt * 1 / mm2pt(1) # (25.4 / 72)
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
74
|
+
# rubocop: enable Naming/MethodParameterName
|
data/lib/prawn/outline.rb
CHANGED
@@ -1,26 +1,28 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Prawn
|
4
4
|
class Document
|
5
5
|
# @group Stable API
|
6
6
|
|
7
|
-
# Lazily instantiates a Prawn::Outline object for document. This is used as
|
8
|
-
# to methods to build the outline tree for a document's table
|
7
|
+
# Lazily instantiates a Prawn::Outline object for document. This is used as
|
8
|
+
# point of entry to methods to build the outline tree for a document's table
|
9
|
+
# of contents.
|
9
10
|
def outline
|
10
11
|
@outline ||= Outline.new(self)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
14
15
|
# The Outline class organizes the outline tree items for the document.
|
15
|
-
# Note that the prev and parent instance variables are adjusted while
|
16
|
-
# through the nested blocks. These variables along with the
|
17
|
-
# of blocks are the primary means by which the relations
|
18
|
-
# OutlineItems and the OutlineRoot are set. Unfortunately, the
|
19
|
-
# understand how this works is to follow the method calls through
|
16
|
+
# Note that the prev and parent instance variables are adjusted while
|
17
|
+
# navigating through the nested blocks. These variables along with the
|
18
|
+
# presence or absense of blocks are the primary means by which the relations
|
19
|
+
# for the various OutlineItems and the OutlineRoot are set. Unfortunately, the
|
20
|
+
# best way to understand how this works is to follow the method calls through
|
21
|
+
# a real example.
|
20
22
|
#
|
21
|
-
# Some ideas for the organization of this class were gleaned from name_tree.
|
22
|
-
# particular the way in which the OutlineItems are finally rendered into
|
23
|
-
# objects in PdfObject through a hash.
|
23
|
+
# Some ideas for the organization of this class were gleaned from name_tree.
|
24
|
+
# In particular the way in which the OutlineItems are finally rendered into
|
25
|
+
# document objects in PdfObject through a hash.
|
24
26
|
#
|
25
27
|
class Outline
|
26
28
|
# @private
|
@@ -42,10 +44,11 @@ module Prawn
|
|
42
44
|
|
43
45
|
# Defines/Updates an outline for the document.
|
44
46
|
# The outline is an optional nested index that appears on the side of a PDF
|
45
|
-
# document usually with direct links to pages. The outline DSL is defined by
|
46
|
-
# blocks involving two methods: section and page; see the
|
47
|
-
# for their arguments and options. Note that
|
48
|
-
# to add more sections to the end of the
|
47
|
+
# document usually with direct links to pages. The outline DSL is defined by
|
48
|
+
# nested blocks involving two methods: section and page; see the
|
49
|
+
# documentation on those methods for their arguments and options. Note that
|
50
|
+
# one can also use outline#update to add more sections to the end of the
|
51
|
+
# outline tree using the same syntax and scope.
|
49
52
|
#
|
50
53
|
# The syntax is best illustrated with an example:
|
51
54
|
#
|
@@ -69,28 +72,31 @@ module Prawn
|
|
69
72
|
# end
|
70
73
|
#
|
71
74
|
def define(&block)
|
72
|
-
instance_eval(&block)
|
75
|
+
instance_eval(&block) if block
|
73
76
|
end
|
74
77
|
|
75
|
-
alias
|
78
|
+
alias update define
|
76
79
|
|
77
80
|
# Inserts an outline section to the outline tree (see outline#define).
|
78
81
|
# Although you will probably choose to exclusively use outline#define so
|
79
|
-
# that your outline tree is contained and easy to manage, this method
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
82
|
+
# that your outline tree is contained and easy to manage, this method gives
|
83
|
+
# you the option to insert sections to the outline tree at any point during
|
84
|
+
# document generation. This method allows you to add a child subsection to
|
85
|
+
# any other item at any level in the outline tree. Currently the only way
|
86
|
+
# to locate the place of entry is with the title for the item. If your title
|
87
|
+
# names are not unique consider using define_outline.
|
85
88
|
# The method takes the following arguments:
|
86
|
-
# title: a string that must match an outline title to add
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
89
|
+
# title: a string that must match an outline title to add
|
90
|
+
# the subsection to
|
91
|
+
# position: either :first or :last (the default) where the subsection will
|
92
|
+
# be placed relative to other child elements. If you need to position
|
93
|
+
# your subsection in between other elements then consider using
|
94
|
+
# #insert_section_after
|
90
95
|
# block: uses the same DSL syntax as outline#define, for example:
|
91
96
|
#
|
92
|
-
# Consider using this method inside of outline.update if you want to have
|
93
|
-
# to be scoped as self (see #insert_section_after
|
97
|
+
# Consider using this method inside of outline.update if you want to have
|
98
|
+
# the outline object to be scoped as self (see #insert_section_after
|
99
|
+
# example).
|
94
100
|
#
|
95
101
|
# go_to_page 2
|
96
102
|
# start_new_page
|
@@ -101,8 +107,10 @@ module Prawn
|
|
101
107
|
#
|
102
108
|
def add_subsection_to(title, position = :last, &block)
|
103
109
|
@parent = items[title]
|
104
|
-
|
105
|
-
|
110
|
+
unless @parent
|
111
|
+
raise Prawn::Errors::UnknownOutlineTitle,
|
112
|
+
"\n No outline item with title: '#{title}' exists in the outline tree"
|
113
|
+
end
|
106
114
|
@prev = position == :first ? nil : @parent.data.last
|
107
115
|
nxt = position == :first ? @parent.data.first : nil
|
108
116
|
insert_section(nxt, &block)
|
@@ -110,12 +118,13 @@ module Prawn
|
|
110
118
|
|
111
119
|
# Inserts an outline section to the outline tree (see outline#define).
|
112
120
|
# Although you will probably choose to exclusively use outline#define so
|
113
|
-
# that your outline tree is contained and easy to manage, this method
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
# Currently the only way to locate the place of entry is with the title for
|
118
|
-
# item. If your title names are not unique consider using
|
121
|
+
# that your outline tree is contained and easy to manage, this method gives
|
122
|
+
# you the option to insert sections to the outline tree at any point during
|
123
|
+
# document generation. Unlike outline.add_section, this method allows you to
|
124
|
+
# enter a section after any other item at any level in the outline tree.
|
125
|
+
# Currently the only way to locate the place of entry is with the title for
|
126
|
+
# the item. If your title names are not unique consider using
|
127
|
+
# define_outline.
|
119
128
|
# The method takes the following arguments:
|
120
129
|
# title: the title of other section or page to insert new section after
|
121
130
|
# block: uses the same DSL syntax as outline#define, for example:
|
@@ -131,30 +140,36 @@ module Prawn
|
|
131
140
|
#
|
132
141
|
def insert_section_after(title, &block)
|
133
142
|
@prev = items[title]
|
134
|
-
|
135
|
-
|
143
|
+
unless @prev
|
144
|
+
raise Prawn::Errors::UnknownOutlineTitle,
|
145
|
+
"\n No outline item with title: '#{title}' exists in the outline tree"
|
146
|
+
end
|
136
147
|
@parent = @prev.data.parent
|
137
148
|
nxt = @prev.data.next
|
138
149
|
insert_section(nxt, &block)
|
139
150
|
end
|
140
151
|
|
141
|
-
# See outline#define above for documentation on how this is used in that
|
152
|
+
# See outline#define above for documentation on how this is used in that
|
153
|
+
# context
|
142
154
|
#
|
143
155
|
# Adds an outine section to the outline tree.
|
144
156
|
# Although you will probably choose to exclusively use outline#define so
|
145
|
-
# that your outline tree is contained and easy to manage, this method
|
146
|
-
#
|
147
|
-
#
|
148
|
-
# the section will be added at the top level after the other root
|
149
|
-
# For more flexible placement try using
|
150
|
-
# outline#add_subsection_to
|
157
|
+
# that your outline tree is contained and easy to manage, this method gives
|
158
|
+
# you the option to add sections to the outline tree at any point during
|
159
|
+
# document generation. When not being called from within another #section
|
160
|
+
# block the section will be added at the top level after the other root
|
161
|
+
# elements of the outline. For more flexible placement try using
|
162
|
+
# outline#insert_section_after and/or outline#add_subsection_to
|
163
|
+
#
|
151
164
|
# Takes the following arguments:
|
152
165
|
# title: the outline text that appears for the section.
|
153
|
-
# options: destination - optional integer defining the page number for
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
166
|
+
# options: destination - optional integer defining the page number for
|
167
|
+
# a destination link to the top of the page (using a :FIT
|
168
|
+
# destination).
|
169
|
+
# - or an array with a custom destination (see the #dest_*
|
170
|
+
# methods of the PDF::Destination module)
|
171
|
+
# closed - whether the section should show its nested outline
|
172
|
+
# elements.
|
158
173
|
# - defaults to false.
|
159
174
|
# block: more nested subsections and/or page blocks
|
160
175
|
#
|
@@ -167,36 +182,40 @@ module Prawn
|
|
167
182
|
add_outline_item(title, options, &block)
|
168
183
|
end
|
169
184
|
|
170
|
-
# See Outline#define above for more documentation on how it is used in that
|
185
|
+
# See Outline#define above for more documentation on how it is used in that
|
186
|
+
# context
|
171
187
|
#
|
172
188
|
# Adds a page to the outline.
|
173
189
|
# Although you will probably choose to exclusively use outline#define so
|
174
190
|
# that your outline tree is contained and easy to manage, this method also
|
175
191
|
# gives you the option to add pages to the root of outline tree at any point
|
176
|
-
# during document generation. Note that the page will be added at the
|
177
|
-
#
|
178
|
-
# using outline#insert_section_after and/or outline#add_subsection_to.
|
192
|
+
# during document generation. Note that the page will be added at the top
|
193
|
+
# level after the other root outline elements. For more flexible placement
|
194
|
+
# try using outline#insert_section_after and/or outline#add_subsection_to.
|
179
195
|
#
|
180
196
|
# Takes the following arguments:
|
181
|
-
#
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
185
|
-
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
197
|
+
# options:
|
198
|
+
# title - REQUIRED. The outline text that appears for the page.
|
199
|
+
# destination - optional integer defining the page number for
|
200
|
+
# a destination link to the top of the page (using a :FIT
|
201
|
+
# destination).
|
202
|
+
# or an array with a custom destination (see the dest_* methods
|
203
|
+
# of the PDF::Destination module)
|
204
|
+
# closed - whether the section should show its nested outline elements.
|
205
|
+
# - defaults to false.
|
189
206
|
# example usage:
|
190
207
|
#
|
191
208
|
# outline.page :title => "Very Last Page"
|
192
|
-
#
|
193
|
-
#
|
209
|
+
#
|
210
|
+
# Note: this method is almost identical to section except that it does not
|
211
|
+
# accept a block thereby defining the outline item as a leaf on the outline
|
212
|
+
# tree structure.
|
194
213
|
def page(options = {})
|
195
214
|
if options[:title]
|
196
215
|
title = options[:title]
|
197
216
|
else
|
198
|
-
|
199
|
-
|
217
|
+
raise Prawn::Errors::RequiredOption,
|
218
|
+
"\nTitle is a required option for page"
|
200
219
|
end
|
201
220
|
add_outline_item(title, options)
|
202
221
|
end
|
@@ -207,15 +226,16 @@ module Prawn
|
|
207
226
|
# lazily initialized, so that documents that do not have an outline
|
208
227
|
# do not incur the additional overhead.
|
209
228
|
def root
|
210
|
-
document.state.store.root.data[:Outlines] ||=
|
229
|
+
document.state.store.root.data[:Outlines] ||=
|
230
|
+
document.ref!(PDF::Core::OutlineRoot.new)
|
211
231
|
end
|
212
232
|
|
213
233
|
def add_outline_item(title, options, &block)
|
214
234
|
outline_item = create_outline_item(title, options)
|
215
|
-
|
235
|
+
establish_relations(outline_item)
|
216
236
|
increase_count
|
217
237
|
set_variables_for_block(outline_item, block)
|
218
|
-
|
238
|
+
yield if block
|
219
239
|
reset_parent(outline_item)
|
220
240
|
end
|
221
241
|
|
@@ -234,7 +254,7 @@ module Prawn
|
|
234
254
|
items[title] = document.ref!(outline_item)
|
235
255
|
end
|
236
256
|
|
237
|
-
def
|
257
|
+
def establish_relations(outline_item)
|
238
258
|
prev.data.next = outline_item if prev
|
239
259
|
parent.data.first = outline_item unless prev
|
240
260
|
parent.data.last = outline_item
|
@@ -244,11 +264,11 @@ module Prawn
|
|
244
264
|
counting_parent = parent
|
245
265
|
while counting_parent
|
246
266
|
counting_parent.data.count += 1
|
247
|
-
if counting_parent == root
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
267
|
+
counting_parent = if counting_parent == root
|
268
|
+
nil
|
269
|
+
else
|
270
|
+
counting_parent.data.parent
|
271
|
+
end
|
252
272
|
end
|
253
273
|
end
|
254
274
|
|
@@ -267,7 +287,7 @@ module Prawn
|
|
267
287
|
def insert_section(nxt, &block)
|
268
288
|
last = @parent.data.last
|
269
289
|
if block
|
270
|
-
|
290
|
+
yield
|
271
291
|
end
|
272
292
|
adjust_relations(nxt, last)
|
273
293
|
reset_root_positioning
|
data/lib/prawn/repeater.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
3
|
# repeater.rb : Implements repeated page elements.
|
4
4
|
# Heavy inspired by repeating_element() in PDF::Wrapper
|
5
5
|
# http://pdf-wrapper.rubyforge.org/
|
@@ -20,9 +20,9 @@ module Prawn
|
|
20
20
|
|
21
21
|
# @group Experimental API
|
22
22
|
|
23
|
-
# Provides a way to execute a block of code repeatedly based on
|
24
|
-
# page_filter. Since Stamp is used under the hood, this method is very
|
25
|
-
# efficient.
|
23
|
+
# Provides a way to execute a block of code repeatedly based on
|
24
|
+
# a page_filter. Since Stamp is used under the hood, this method is very
|
25
|
+
# space efficient.
|
26
26
|
#
|
27
27
|
# Available page filters are:
|
28
28
|
# :all -- repeats on every page
|
@@ -32,8 +32,9 @@ module Prawn
|
|
32
32
|
# some_range -- repeats on every page included in the range
|
33
33
|
# some_lambda -- yields page number and repeats for true return values
|
34
34
|
#
|
35
|
-
# Also accepts an optional second argument for dynamic content which
|
36
|
-
# in the context of the filtered pages without using
|
35
|
+
# Also accepts an optional second argument for dynamic content which
|
36
|
+
# executes the code in the context of the filtered pages without using
|
37
|
+
# a Stamp.
|
37
38
|
#
|
38
39
|
# Example:
|
39
40
|
#
|
@@ -75,7 +76,10 @@ module Prawn
|
|
75
76
|
# end
|
76
77
|
#
|
77
78
|
def repeat(page_filter, options = {}, &block)
|
78
|
-
|
79
|
+
dynamic = options.fetch(:dynamic, false)
|
80
|
+
repeaters << Prawn::Repeater.new(
|
81
|
+
self, page_filter, dynamic, &block
|
82
|
+
)
|
79
83
|
end
|
80
84
|
end
|
81
85
|
|
@@ -91,10 +95,10 @@ module Prawn
|
|
91
95
|
attr_reader :name
|
92
96
|
|
93
97
|
def initialize(document, page_filter, dynamic = false, &block)
|
94
|
-
@document
|
98
|
+
@document = document
|
95
99
|
@page_filter = page_filter
|
96
100
|
@dynamic = dynamic
|
97
|
-
@stamp_name
|
101
|
+
@stamp_name = "prawn_repeater(#{Repeater.count})"
|
98
102
|
@document.create_stamp(@stamp_name, &block) unless dynamic
|
99
103
|
@block = block if dynamic
|
100
104
|
@graphic_state = document.state.page.graphic_state.dup
|
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.
|
@@ -8,8 +8,6 @@
|
|
8
8
|
|
9
9
|
require 'digest/md5'
|
10
10
|
|
11
|
-
require 'pdf/core/byte_string'
|
12
|
-
|
13
11
|
require_relative 'security/arcfour'
|
14
12
|
|
15
13
|
module Prawn
|
@@ -88,14 +86,14 @@ module Prawn
|
|
88
86
|
# PDF format.
|
89
87
|
#
|
90
88
|
def encrypt_document(options = {})
|
91
|
-
Prawn.verify_options [
|
92
|
-
|
93
|
-
@user_password = options.delete(:user_password) ||
|
89
|
+
Prawn.verify_options %i[user_password owner_password permissions],
|
90
|
+
options
|
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) || {}
|
@@ -124,32 +122,41 @@ module Prawn
|
|
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
|
-
|
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
|
140
143
|
|
141
|
-
|
144
|
+
FULL_PERMISSIONS = 0b1111_1111_1111_1111_1111_1111_1111_1111
|
145
|
+
private_constant :FULL_PERMISSIONS
|
142
146
|
|
143
147
|
def permissions=(perms = {})
|
144
|
-
@permissions ||=
|
148
|
+
@permissions ||= FULL_PERMISSIONS
|
145
149
|
perms.each do |key, value|
|
146
|
-
unless
|
147
|
-
|
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,17 +167,17 @@ 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
|
@@ -178,7 +185,7 @@ module Prawn
|
|
178
185
|
md5 = Digest::MD5.new
|
179
186
|
md5 << pad_password(@user_password)
|
180
187
|
md5 << owner_password_hash
|
181
|
-
md5 << [permissions_value].pack(
|
188
|
+
md5 << [permissions_value].pack('V')
|
182
189
|
md5.digest[0, 5]
|
183
190
|
end
|
184
191
|
end
|
@@ -193,7 +200,7 @@ module Prawn
|
|
193
200
|
|
194
201
|
# The U (user) value in the encryption dictionary. Algorithm 3.4.
|
195
202
|
def user_password_hash
|
196
|
-
Arcfour.new(user_encryption_key).encrypt(
|
203
|
+
Arcfour.new(user_encryption_key).encrypt(PASSWORD_PADDING)
|
197
204
|
end
|
198
205
|
end
|
199
206
|
end
|
@@ -204,46 +211,53 @@ module PDF
|
|
204
211
|
module Core
|
205
212
|
module_function
|
206
213
|
|
207
|
-
# Like
|
214
|
+
# Like pdf_object, but returns an encrypted result if required.
|
208
215
|
# For direct objects, requires the object identifier and generation number
|
209
216
|
# from the indirect object referencing obj.
|
210
217
|
#
|
211
218
|
# @private
|
212
|
-
def
|
219
|
+
def encrypted_pdf_object(obj, key, id, gen, in_content_stream = false)
|
213
220
|
case obj
|
214
221
|
when Array
|
215
|
-
|
216
|
-
|
217
|
-
|
222
|
+
'[' + obj.map do |e|
|
223
|
+
encrypted_pdf_object(e, key, id, gen, in_content_stream)
|
224
|
+
end.join(' ') + ']'
|
218
225
|
when LiteralString
|
219
|
-
obj = ByteString.new(
|
226
|
+
obj = ByteString.new(
|
227
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
228
|
+
).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
|
220
229
|
"(#{obj})"
|
221
230
|
when Time
|
222
|
-
obj = obj.strftime(
|
223
|
-
obj = ByteString.new(
|
231
|
+
obj = obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop + "'00'"
|
232
|
+
obj = ByteString.new(
|
233
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
234
|
+
).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
|
224
235
|
"(#{obj})"
|
225
236
|
when String
|
226
|
-
|
237
|
+
pdf_object(
|
227
238
|
ByteString.new(
|
228
|
-
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
229
|
-
|
239
|
+
Prawn::Document::Security.encrypt_string(obj, key, id, gen)
|
240
|
+
),
|
241
|
+
in_content_stream
|
242
|
+
)
|
230
243
|
when ::Hash
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
244
|
+
'<< ' +
|
245
|
+
obj.map do |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) + ' ' +
|
251
|
+
encrypted_pdf_object(v, key, id, gen, in_content_stream) + "\n"
|
252
|
+
end.join('') +
|
253
|
+
'>>'
|
240
254
|
when NameTree::Value
|
241
|
-
|
242
|
-
|
255
|
+
pdf_object(obj.name) + ' ' +
|
256
|
+
encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)
|
243
257
|
when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
|
244
|
-
|
245
|
-
else # delegate back to
|
246
|
-
|
258
|
+
encrypted_pdf_object(obj.to_hash, key, id, gen, in_content_stream)
|
259
|
+
else # delegate back to pdf_object
|
260
|
+
pdf_object(obj, in_content_stream)
|
247
261
|
end
|
248
262
|
end
|
249
263
|
|
@@ -251,7 +265,10 @@ module PDF
|
|
251
265
|
class Stream
|
252
266
|
def encrypted_object(key, id, gen)
|
253
267
|
if filtered_stream
|
254
|
-
"stream\n
|
268
|
+
"stream\n" +
|
269
|
+
Prawn::Document::Security.encrypt_string(
|
270
|
+
filtered_stream, key, id, gen
|
271
|
+
) + "\nendstream\n"
|
255
272
|
else
|
256
273
|
''
|
257
274
|
end
|
@@ -263,13 +280,16 @@ module PDF
|
|
263
280
|
# Returns the object definition for the object this references, keyed from
|
264
281
|
# +key+.
|
265
282
|
def encrypted_object(key)
|
266
|
-
@on_encode
|
283
|
+
@on_encode&.call(self)
|
267
284
|
|
268
|
-
output = "#{@identifier} #{gen} obj\n"
|
285
|
+
output = +"#{@identifier} #{gen} obj\n"
|
269
286
|
if @stream.empty?
|
270
|
-
output <<
|
287
|
+
output <<
|
288
|
+
PDF::Core.encrypted_pdf_object(data, key, @identifier, gen) << "\n"
|
271
289
|
else
|
272
|
-
output << PDF::Core
|
290
|
+
output << PDF::Core.encrypted_pdf_object(
|
291
|
+
data.merge(@stream.data), key, @identifier, gen
|
292
|
+
) << "\n" <<
|
273
293
|
@stream.encrypted_object(key, @identifier, gen)
|
274
294
|
end
|
275
295
|
|