prawn 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/prawn/document/bounding_box.rb +213 -141
  4. data/lib/prawn/document/column_box.rb +61 -26
  5. data/lib/prawn/document/internals.rb +25 -16
  6. data/lib/prawn/document/span.rb +20 -18
  7. data/lib/prawn/document.rb +257 -171
  8. data/lib/prawn/encoding.rb +2 -5
  9. data/lib/prawn/errors.rb +23 -34
  10. data/lib/prawn/font.rb +248 -135
  11. data/lib/prawn/font_metric_cache.rb +11 -10
  12. data/lib/prawn/fonts/afm.rb +85 -45
  13. data/lib/prawn/fonts/dfont.rb +7 -1
  14. data/lib/prawn/fonts/otf.rb +4 -1
  15. data/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
  16. data/lib/prawn/fonts/ttc.rb +7 -2
  17. data/lib/prawn/fonts/ttf.rb +305 -93
  18. data/lib/prawn/fonts.rb +14 -0
  19. data/lib/prawn/graphics/blend_mode.rb +25 -28
  20. data/lib/prawn/graphics/cap_style.rb +9 -12
  21. data/lib/prawn/graphics/color.rb +57 -34
  22. data/lib/prawn/graphics/dash.rb +45 -42
  23. data/lib/prawn/graphics/join_style.rb +17 -11
  24. data/lib/prawn/graphics/patterns.rb +190 -69
  25. data/lib/prawn/graphics/transformation.rb +48 -41
  26. data/lib/prawn/graphics/transparency.rb +16 -40
  27. data/lib/prawn/graphics.rb +363 -253
  28. data/lib/prawn/grid.rb +184 -57
  29. data/lib/prawn/image_handler.rb +27 -10
  30. data/lib/prawn/images/image.rb +8 -10
  31. data/lib/prawn/images/jpg.rb +42 -19
  32. data/lib/prawn/images/png.rb +92 -41
  33. data/lib/prawn/images.rb +44 -57
  34. data/lib/prawn/measurement_extensions.rb +39 -8
  35. data/lib/prawn/measurements.rb +60 -5
  36. data/lib/prawn/outline.rb +114 -108
  37. data/lib/prawn/repeater.rb +51 -35
  38. data/lib/prawn/security/arcfour.rb +4 -4
  39. data/lib/prawn/security.rb +75 -70
  40. data/lib/prawn/soft_mask.rb +42 -30
  41. data/lib/prawn/stamp.rb +38 -42
  42. data/lib/prawn/text/box.rb +146 -96
  43. data/lib/prawn/text/formatted/arranger.rb +87 -26
  44. data/lib/prawn/text/formatted/box.rb +221 -150
  45. data/lib/prawn/text/formatted/fragment.rb +130 -14
  46. data/lib/prawn/text/formatted/line_wrap.rb +33 -24
  47. data/lib/prawn/text/formatted/parser.rb +112 -72
  48. data/lib/prawn/text/formatted/wrap.rb +12 -17
  49. data/lib/prawn/text/formatted.rb +75 -0
  50. data/lib/prawn/text.rb +441 -196
  51. data/lib/prawn/transformation_stack.rb +29 -10
  52. data/lib/prawn/utilities.rb +13 -13
  53. data/lib/prawn/version.rb +2 -1
  54. data/lib/prawn/view.rb +68 -53
  55. data/lib/prawn.rb +23 -18
  56. data.tar.gz.sig +0 -0
  57. metadata +54 -177
  58. metadata.gz.sig +0 -0
  59. data/.yardopts +0 -10
  60. data/Gemfile +0 -5
  61. data/Rakefile +0 -25
  62. data/manual/absolute_position.pdf +0 -0
  63. data/manual/basic_concepts/adding_pages.rb +0 -26
  64. data/manual/basic_concepts/basic_concepts.rb +0 -43
  65. data/manual/basic_concepts/creation.rb +0 -38
  66. data/manual/basic_concepts/cursor.rb +0 -32
  67. data/manual/basic_concepts/measurement.rb +0 -24
  68. data/manual/basic_concepts/origin.rb +0 -37
  69. data/manual/basic_concepts/other_cursor_helpers.rb +0 -39
  70. data/manual/basic_concepts/view.rb +0 -48
  71. data/manual/bounding_box/bounding_box.rb +0 -41
  72. data/manual/bounding_box/bounds.rb +0 -48
  73. data/manual/bounding_box/canvas.rb +0 -23
  74. data/manual/bounding_box/creation.rb +0 -22
  75. data/manual/bounding_box/indentation.rb +0 -45
  76. data/manual/bounding_box/nesting.rb +0 -52
  77. data/manual/bounding_box/russian_boxes.rb +0 -40
  78. data/manual/bounding_box/stretchy.rb +0 -29
  79. data/manual/contents.rb +0 -35
  80. data/manual/cover.rb +0 -43
  81. data/manual/document_and_page_options/background.rb +0 -29
  82. data/manual/document_and_page_options/document_and_page_options.rb +0 -34
  83. data/manual/document_and_page_options/metadata.rb +0 -25
  84. data/manual/document_and_page_options/page_margins.rb +0 -36
  85. data/manual/document_and_page_options/page_size.rb +0 -34
  86. data/manual/document_and_page_options/print_scaling.rb +0 -23
  87. data/manual/example_helper.rb +0 -8
  88. data/manual/graphics/blend_mode.rb +0 -52
  89. data/manual/graphics/circle_and_ellipse.rb +0 -21
  90. data/manual/graphics/color.rb +0 -22
  91. data/manual/graphics/common_lines.rb +0 -29
  92. data/manual/graphics/fill_and_stroke.rb +0 -41
  93. data/manual/graphics/fill_rules.rb +0 -38
  94. data/manual/graphics/gradients.rb +0 -43
  95. data/manual/graphics/graphics.rb +0 -64
  96. data/manual/graphics/helper.rb +0 -34
  97. data/manual/graphics/line_width.rb +0 -36
  98. data/manual/graphics/lines_and_curves.rb +0 -40
  99. data/manual/graphics/polygon.rb +0 -27
  100. data/manual/graphics/rectangle.rb +0 -20
  101. data/manual/graphics/rotate.rb +0 -25
  102. data/manual/graphics/scale.rb +0 -42
  103. data/manual/graphics/soft_masks.rb +0 -44
  104. data/manual/graphics/stroke_cap.rb +0 -30
  105. data/manual/graphics/stroke_dash.rb +0 -47
  106. data/manual/graphics/stroke_join.rb +0 -29
  107. data/manual/graphics/translate.rb +0 -29
  108. data/manual/graphics/transparency.rb +0 -33
  109. data/manual/how_to_read_this_manual.rb +0 -39
  110. data/manual/images/absolute_position.rb +0 -22
  111. data/manual/images/fit.rb +0 -20
  112. data/manual/images/horizontal.rb +0 -24
  113. data/manual/images/images.rb +0 -41
  114. data/manual/images/plain_image.rb +0 -17
  115. data/manual/images/scale.rb +0 -21
  116. data/manual/images/vertical.rb +0 -30
  117. data/manual/images/width_and_height.rb +0 -24
  118. data/manual/layout/boxes.rb +0 -26
  119. data/manual/layout/content.rb +0 -24
  120. data/manual/layout/layout.rb +0 -27
  121. data/manual/layout/simple_grid.rb +0 -22
  122. data/manual/outline/add_subsection_to.rb +0 -60
  123. data/manual/outline/insert_section_after.rb +0 -46
  124. data/manual/outline/outline.rb +0 -33
  125. data/manual/outline/sections_and_pages.rb +0 -66
  126. data/manual/repeatable_content/alternate_page_numbering.rb +0 -36
  127. data/manual/repeatable_content/page_numbering.rb +0 -55
  128. data/manual/repeatable_content/repeatable_content.rb +0 -35
  129. data/manual/repeatable_content/repeater.rb +0 -54
  130. data/manual/repeatable_content/stamp.rb +0 -40
  131. data/manual/security/encryption.rb +0 -28
  132. data/manual/security/permissions.rb +0 -43
  133. data/manual/security/security.rb +0 -28
  134. data/manual/table.rb +0 -16
  135. data/manual/text/alignment.rb +0 -43
  136. data/manual/text/color.rb +0 -24
  137. data/manual/text/column_box.rb +0 -30
  138. data/manual/text/fallback_fonts.rb +0 -41
  139. data/manual/text/font.rb +0 -40
  140. data/manual/text/font_size.rb +0 -44
  141. data/manual/text/font_style.rb +0 -25
  142. data/manual/text/formatted_callbacks.rb +0 -70
  143. data/manual/text/formatted_text.rb +0 -61
  144. data/manual/text/free_flowing_text.rb +0 -50
  145. data/manual/text/inline.rb +0 -40
  146. data/manual/text/kerning_and_character_spacing.rb +0 -38
  147. data/manual/text/leading.rb +0 -24
  148. data/manual/text/line_wrapping.rb +0 -60
  149. data/manual/text/paragraph_indentation.rb +0 -31
  150. data/manual/text/positioned_text.rb +0 -37
  151. data/manual/text/registering_families.rb +0 -51
  152. data/manual/text/rendering_and_color.rb +0 -36
  153. data/manual/text/right_to_left_text.rb +0 -54
  154. data/manual/text/rotation.rb +0 -52
  155. data/manual/text/single_usage.rb +0 -36
  156. data/manual/text/text.rb +0 -75
  157. data/manual/text/text_box_excess.rb +0 -35
  158. data/manual/text/text_box_extensions.rb +0 -48
  159. data/manual/text/text_box_overflow.rb +0 -51
  160. data/manual/text/utf8.rb +0 -27
  161. data/manual/text/win_ansi_charset.rb +0 -62
  162. data/prawn.gemspec +0 -51
  163. data/spec/data/curves.pdf +0 -66
  164. data/spec/extensions/encoding_helpers.rb +0 -11
  165. data/spec/prawn/document/bounding_box_spec.rb +0 -550
  166. data/spec/prawn/document/column_box_spec.rb +0 -75
  167. data/spec/prawn/document/security_spec.rb +0 -176
  168. data/spec/prawn/document_annotations_spec.rb +0 -76
  169. data/spec/prawn/document_destinations_spec.rb +0 -15
  170. data/spec/prawn/document_grid_spec.rb +0 -99
  171. data/spec/prawn/document_reference_spec.rb +0 -27
  172. data/spec/prawn/document_span_spec.rb +0 -44
  173. data/spec/prawn/document_spec.rb +0 -805
  174. data/spec/prawn/font_metric_cache_spec.rb +0 -54
  175. data/spec/prawn/font_spec.rb +0 -544
  176. data/spec/prawn/graphics/blend_mode_spec.rb +0 -63
  177. data/spec/prawn/graphics/transparency_spec.rb +0 -81
  178. data/spec/prawn/graphics_spec.rb +0 -872
  179. data/spec/prawn/graphics_stroke_styles_spec.rb +0 -229
  180. data/spec/prawn/image_handler_spec.rb +0 -53
  181. data/spec/prawn/images/jpg_spec.rb +0 -20
  182. data/spec/prawn/images/png_spec.rb +0 -283
  183. data/spec/prawn/images_spec.rb +0 -229
  184. data/spec/prawn/measurements_extensions_spec.rb +0 -24
  185. data/spec/prawn/outline_spec.rb +0 -512
  186. data/spec/prawn/repeater_spec.rb +0 -166
  187. data/spec/prawn/soft_mask_spec.rb +0 -74
  188. data/spec/prawn/stamp_spec.rb +0 -173
  189. data/spec/prawn/text/box_spec.rb +0 -1110
  190. data/spec/prawn/text/formatted/arranger_spec.rb +0 -466
  191. data/spec/prawn/text/formatted/box_spec.rb +0 -849
  192. data/spec/prawn/text/formatted/fragment_spec.rb +0 -343
  193. data/spec/prawn/text/formatted/line_wrap_spec.rb +0 -495
  194. data/spec/prawn/text/formatted/parser_spec.rb +0 -697
  195. data/spec/prawn/text_draw_text_spec.rb +0 -150
  196. data/spec/prawn/text_rendering_mode_spec.rb +0 -48
  197. data/spec/prawn/text_spacing_spec.rb +0 -95
  198. data/spec/prawn/text_spec.rb +0 -603
  199. data/spec/prawn/text_with_inline_formatting_spec.rb +0 -35
  200. data/spec/prawn/transformation_stack_spec.rb +0 -66
  201. data/spec/prawn/view_spec.rb +0 -63
  202. data/spec/prawn_manual_spec.rb +0 -35
  203. data/spec/spec_helper.rb +0 -48
@@ -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
- # detailed in the PDF Reference 1.3, section 3.5 "Encryption", and it is
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
- # +options+ can contain the following:
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
- # encrypt_document :permissions => { :print_document => false },
62
- # :owner_password => :random
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
- # encrypt_document :user_password => 'foo', :owner_password => 'bar'
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
- # encrypt_document
38
+ # ```ruby
39
+ # encrypt_document
40
+ # ```
73
41
  #
74
- # == Caveats
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 %i[user_password owner_password permissions],
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
- # object ID and generation number of the reference.
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]
@@ -128,7 +124,7 @@ module Prawn
128
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
 
@@ -210,7 +206,7 @@ end
210
206
 
211
207
  # @private
212
208
  module PDF
213
- module Core
209
+ module Core # rubocop: disable Style/Documentation
214
210
  module_function
215
211
 
216
212
  # Like pdf_object, but returns an encrypted result if required.
@@ -221,38 +217,38 @@ module PDF
221
217
  def encrypted_pdf_object(obj, key, id, gen, in_content_stream = false)
222
218
  case obj
223
219
  when Array
224
- array_content = obj.map do |e|
220
+ array_content = obj.map { |e|
225
221
  encrypted_pdf_object(e, key, id, gen, in_content_stream)
226
- end.join(' ')
222
+ }.join(' ')
227
223
  "[#{array_content}]"
228
224
  when LiteralString
229
225
  obj =
230
226
  ByteString.new(
231
- Prawn::Document::Security.encrypt_string(obj, key, id, gen)
232
- ).gsub(/[\\\n()]/) { |m| "\\#{m}" }
227
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen),
228
+ ).gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
233
229
  "(#{obj})"
234
230
  when Time
235
231
  obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
236
232
  obj =
237
233
  ByteString.new(
238
- Prawn::Document::Security.encrypt_string(obj, key, id, gen)
239
- ).gsub(/[\\\n()]/) { |m| "\\#{m}" }
234
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen),
235
+ ).gsub(/[\\\r()]/, STRING_ESCAPE_MAP)
240
236
  "(#{obj})"
241
237
  when String
242
238
  pdf_object(
243
239
  ByteString.new(
244
- Prawn::Document::Security.encrypt_string(obj, key, id, gen)
240
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen),
245
241
  ),
246
- in_content_stream
242
+ in_content_stream,
247
243
  )
248
244
  when ::Hash
249
- hash_content = obj.map do |k, v|
245
+ hash_content = obj.map { |k, v|
250
246
  unless k.is_a?(String) || k.is_a?(Symbol)
251
247
  raise PDF::Core::Errors::FailedObjectConversion,
252
248
  'A PDF Dictionary must be keyed by names'
253
249
  end
254
250
  "#{pdf_object(k.to_sym, in_content_stream)} #{encrypted_pdf_object(v, key, id, gen, in_content_stream)}\n"
255
- end.join('')
251
+ }.join('')
256
252
  "<< #{hash_content}>>"
257
253
  when NameTree::Value
258
254
  "#{pdf_object(obj.name)} #{encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)}"
@@ -265,11 +261,17 @@ module PDF
265
261
 
266
262
  # @private
267
263
  class Stream
264
+ # Encrypt stream.
265
+ #
266
+ # @param key [String]
267
+ # @param id [Integer]
268
+ # @param gen [Integer]
269
+ # @return [String]
268
270
  def encrypted_object(key, id, gen)
269
271
  if filtered_stream
270
272
  "stream\n#{
271
273
  Prawn::Document::Security.encrypt_string(
272
- filtered_stream, key, id, gen
274
+ filtered_stream, key, id, gen,
273
275
  )
274
276
  }\nendstream\n"
275
277
  else
@@ -281,7 +283,10 @@ module PDF
281
283
  # @private
282
284
  class Reference
283
285
  # Returns the object definition for the object this references, keyed from
284
- # +key+.
286
+ # `key`.
287
+ #
288
+ # @param key [String]
289
+ # @return [String]
285
290
  def encrypted_object(key)
286
291
  @on_encode&.call(self)
287
292
 
@@ -291,7 +296,7 @@ module PDF
291
296
  PDF::Core.encrypted_pdf_object(data, key, @identifier, gen) << "\n"
292
297
  else
293
298
  output << PDF::Core.encrypted_pdf_object(
294
- data.merge(@stream.data), key, @identifier, gen
299
+ data.merge(@stream.data), key, @identifier, gen,
295
300
  ) << "\n" <<
296
301
  @stream.encrypted_object(key, @identifier, gen)
297
302
  end
@@ -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
- # The Prawn::SoftMask module is used to create arbitrary transparency in
12
- # document. Using a soft mask allows creating more visually rich documents.
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 "/#{soft_mask_registry[registry_key]} gs"
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 "/#{id} gs"
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
- # The Prawn::Stamp module is used to create content that will be
11
- # included multiple times in a document. Using a stamp has three
12
- # advantages over creating content anew each time it is placed on
13
- # the page:
14
- # i. faster document creation
15
- # ii. smaller final document
16
- # iii. faster display on subsequent displays of the repeated
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
- # Example:
12
+ # @example
21
13
  # pdf.create_stamp("my_stamp") {
22
14
  # pdf.fill_circle([10, 15], 5)
23
- # pdf.draw_text("hello world", :at => [20, 10])
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 named <tt>name</tt> to the page
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
- # Example:
23
+ # @example
36
24
  # pdf.create_stamp("my_stamp") {
37
25
  # pdf.fill_circle([10, 15], 5)
38
- # pdf.text("hello world", :at => [20, 10])
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 "/#{dictionary_name} Do"
45
- update_annotation_references dictionary.data[:Annots]
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 named <tt>name</tt> at a position offset from
50
- # the initial coords at which the elements of the stamp was
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
- # Example:
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
- # See stamp() for exceptions that might be raised
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 named <tt>name</tt>
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
- # Example:
62
+ # @example
73
63
  # pdf.create_stamp("my_stamp") {
74
64
  # pdf.fill_circle([10, 15], 5)
75
- # pdf.draw_text("hello world", :at => [20, 10])
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