prawn 2.1.0 → 2.2.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.
Files changed (278) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +0 -0
  4. data/Gemfile +1 -9
  5. data/Rakefile +12 -22
  6. data/lib/prawn.rb +29 -48
  7. data/lib/prawn/document.rb +148 -123
  8. data/lib/prawn/document/bounding_box.rb +33 -26
  9. data/lib/prawn/document/column_box.rb +5 -7
  10. data/lib/prawn/document/internals.rb +6 -6
  11. data/lib/prawn/document/span.rb +20 -17
  12. data/lib/prawn/encoding.rb +65 -67
  13. data/lib/prawn/errors.rb +10 -7
  14. data/lib/prawn/font.rb +78 -62
  15. data/lib/prawn/font/afm.rb +93 -66
  16. data/lib/prawn/font/dfont.rb +2 -10
  17. data/lib/prawn/font/ttc.rb +34 -0
  18. data/lib/prawn/font/ttf.rb +73 -65
  19. data/lib/prawn/font_metric_cache.rb +9 -8
  20. data/lib/prawn/graphics.rb +110 -70
  21. data/lib/prawn/graphics/blend_mode.rb +7 -8
  22. data/lib/prawn/graphics/cap_style.rb +2 -4
  23. data/lib/prawn/graphics/color.rb +23 -26
  24. data/lib/prawn/graphics/dash.rb +22 -12
  25. data/lib/prawn/graphics/join_style.rb +8 -4
  26. data/lib/prawn/graphics/patterns.rb +185 -96
  27. data/lib/prawn/graphics/transformation.rb +11 -9
  28. data/lib/prawn/graphics/transparency.rb +15 -13
  29. data/lib/prawn/grid.rb +20 -20
  30. data/lib/prawn/image_handler.rb +4 -6
  31. data/lib/prawn/images.rb +22 -15
  32. data/lib/prawn/images/image.rb +0 -1
  33. data/lib/prawn/images/jpg.rb +26 -22
  34. data/lib/prawn/images/png.rb +60 -57
  35. data/lib/prawn/measurement_extensions.rb +8 -9
  36. data/lib/prawn/measurements.rb +14 -15
  37. data/lib/prawn/outline.rb +96 -78
  38. data/lib/prawn/repeater.rb +12 -10
  39. data/lib/prawn/security.rb +66 -48
  40. data/lib/prawn/security/arcfour.rb +1 -3
  41. data/lib/prawn/soft_mask.rb +23 -25
  42. data/lib/prawn/stamp.rb +16 -12
  43. data/lib/prawn/text.rb +59 -45
  44. data/lib/prawn/text/box.rb +9 -8
  45. data/lib/prawn/text/formatted.rb +4 -6
  46. data/lib/prawn/text/formatted/arranger.rb +51 -30
  47. data/lib/prawn/text/formatted/box.rb +112 -88
  48. data/lib/prawn/text/formatted/fragment.rb +10 -15
  49. data/lib/prawn/text/formatted/line_wrap.rb +118 -61
  50. data/lib/prawn/text/formatted/parser.rb +134 -110
  51. data/lib/prawn/text/formatted/wrap.rb +42 -32
  52. data/lib/prawn/transformation_stack.rb +3 -4
  53. data/lib/prawn/utilities.rb +6 -21
  54. data/lib/prawn/version.rb +1 -3
  55. data/lib/prawn/view.rb +4 -2
  56. data/manual/basic_concepts/adding_pages.rb +4 -7
  57. data/manual/basic_concepts/basic_concepts.rb +29 -22
  58. data/manual/basic_concepts/creation.rb +8 -11
  59. data/manual/basic_concepts/cursor.rb +2 -5
  60. data/manual/basic_concepts/measurement.rb +3 -6
  61. data/manual/basic_concepts/origin.rb +3 -6
  62. data/manual/basic_concepts/other_cursor_helpers.rb +9 -12
  63. data/manual/basic_concepts/view.rb +20 -16
  64. data/manual/bounding_box/bounding_box.rb +27 -24
  65. data/manual/bounding_box/bounds.rb +9 -12
  66. data/manual/bounding_box/canvas.rb +2 -5
  67. data/manual/bounding_box/creation.rb +4 -7
  68. data/manual/bounding_box/indentation.rb +12 -15
  69. data/manual/bounding_box/nesting.rb +22 -17
  70. data/manual/bounding_box/russian_boxes.rb +8 -9
  71. data/manual/bounding_box/stretchy.rb +10 -13
  72. data/manual/contents.rb +26 -22
  73. data/manual/cover.rb +22 -20
  74. data/manual/document_and_page_options/background.rb +9 -13
  75. data/manual/document_and_page_options/document_and_page_options.rb +23 -20
  76. data/manual/document_and_page_options/metadata.rb +16 -16
  77. data/manual/document_and_page_options/page_margins.rb +16 -20
  78. data/manual/document_and_page_options/page_size.rb +11 -12
  79. data/manual/document_and_page_options/print_scaling.rb +15 -15
  80. data/manual/example_helper.rb +2 -4
  81. data/manual/graphics/blend_mode.rb +10 -9
  82. data/manual/graphics/circle_and_ellipse.rb +2 -5
  83. data/manual/graphics/color.rb +5 -9
  84. data/manual/graphics/common_lines.rb +5 -8
  85. data/manual/graphics/fill_and_stroke.rb +2 -5
  86. data/manual/graphics/fill_rules.rb +7 -10
  87. data/manual/graphics/gradients.rb +25 -21
  88. data/manual/graphics/graphics.rb +49 -43
  89. data/manual/graphics/helper.rb +10 -9
  90. data/manual/graphics/line_width.rb +5 -7
  91. data/manual/graphics/lines_and_curves.rb +5 -8
  92. data/manual/graphics/polygon.rb +4 -8
  93. data/manual/graphics/rectangle.rb +2 -5
  94. data/manual/graphics/rotate.rb +4 -7
  95. data/manual/graphics/scale.rb +12 -15
  96. data/manual/graphics/soft_masks.rb +1 -4
  97. data/manual/graphics/stroke_cap.rb +3 -6
  98. data/manual/graphics/stroke_dash.rb +9 -12
  99. data/manual/graphics/stroke_join.rb +2 -5
  100. data/manual/graphics/translate.rb +7 -10
  101. data/manual/graphics/transparency.rb +5 -8
  102. data/manual/how_to_read_this_manual.rb +4 -6
  103. data/manual/images/absolute_position.rb +4 -7
  104. data/manual/images/fit.rb +5 -8
  105. data/manual/images/horizontal.rb +6 -9
  106. data/manual/images/images.rb +25 -23
  107. data/manual/images/plain_image.rb +3 -6
  108. data/manual/images/scale.rb +7 -10
  109. data/manual/images/vertical.rb +10 -13
  110. data/manual/images/width_and_height.rb +8 -11
  111. data/manual/layout/boxes.rb +3 -6
  112. data/manual/layout/content.rb +5 -8
  113. data/manual/layout/layout.rb +16 -16
  114. data/manual/layout/simple_grid.rb +4 -7
  115. data/manual/outline/add_subsection_to.rb +18 -21
  116. data/manual/outline/insert_section_after.rb +13 -16
  117. data/manual/outline/outline.rb +19 -17
  118. data/manual/outline/sections_and_pages.rb +15 -18
  119. data/manual/repeatable_content/alternate_page_numbering.rb +19 -17
  120. data/manual/repeatable_content/page_numbering.rb +15 -16
  121. data/manual/repeatable_content/repeatable_content.rb +23 -19
  122. data/manual/repeatable_content/repeater.rb +12 -15
  123. data/manual/repeatable_content/stamp.rb +12 -15
  124. data/manual/security/encryption.rb +7 -10
  125. data/manual/security/permissions.rb +17 -14
  126. data/manual/security/security.rb +17 -16
  127. data/manual/table.rb +2 -4
  128. data/manual/text/alignment.rb +14 -17
  129. data/manual/text/color.rb +10 -11
  130. data/manual/text/column_box.rb +5 -8
  131. data/manual/text/fallback_fonts.rb +23 -21
  132. data/manual/text/font.rb +9 -12
  133. data/manual/text/font_size.rb +11 -14
  134. data/manual/text/font_style.rb +4 -7
  135. data/manual/text/formatted_callbacks.rb +23 -21
  136. data/manual/text/formatted_text.rb +31 -25
  137. data/manual/text/free_flowing_text.rb +18 -21
  138. data/manual/text/inline.rb +16 -19
  139. data/manual/text/kerning_and_character_spacing.rb +12 -15
  140. data/manual/text/leading.rb +5 -8
  141. data/manual/text/line_wrapping.rb +33 -17
  142. data/manual/text/paragraph_indentation.rb +11 -14
  143. data/manual/text/positioned_text.rb +13 -16
  144. data/manual/text/registering_families.rb +16 -19
  145. data/manual/text/rendering_and_color.rb +7 -10
  146. data/manual/text/right_to_left_text.rb +24 -19
  147. data/manual/text/rotation.rb +26 -23
  148. data/manual/text/single_usage.rb +6 -9
  149. data/manual/text/text.rb +56 -52
  150. data/manual/text/text_box_excess.rb +18 -17
  151. data/manual/text/text_box_extensions.rb +16 -15
  152. data/manual/text/text_box_overflow.rb +15 -18
  153. data/manual/text/utf8.rb +9 -12
  154. data/manual/text/win_ansi_charset.rb +18 -19
  155. data/prawn.gemspec +37 -27
  156. data/spec/extensions/encoding_helpers.rb +0 -2
  157. data/spec/manual_spec.rb +33 -0
  158. data/spec/prawn/document/bounding_box_spec.rb +546 -0
  159. data/spec/prawn/document/column_box_spec.rb +73 -0
  160. data/spec/prawn/document/security_spec.rb +173 -0
  161. data/spec/prawn/document_annotations_spec.rb +74 -0
  162. data/spec/prawn/document_destinations_spec.rb +13 -0
  163. data/spec/prawn/document_grid_spec.rb +96 -0
  164. data/spec/prawn/document_reference_spec.rb +25 -0
  165. data/spec/prawn/document_span_spec.rb +34 -0
  166. data/spec/prawn/document_spec.rb +751 -0
  167. data/spec/prawn/font_metric_cache_spec.rb +52 -0
  168. data/spec/prawn/font_spec.rb +513 -0
  169. data/spec/prawn/graphics/blend_mode_spec.rb +61 -0
  170. data/spec/prawn/graphics/transparency_spec.rb +79 -0
  171. data/spec/prawn/graphics_spec.rb +817 -0
  172. data/spec/prawn/graphics_stroke_styles_spec.rb +227 -0
  173. data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +13 -15
  174. data/spec/prawn/images/jpg_spec.rb +18 -0
  175. data/spec/prawn/images/png_spec.rb +281 -0
  176. data/spec/prawn/images_spec.rb +170 -0
  177. data/spec/prawn/measurements_extensions_spec.rb +22 -0
  178. data/spec/prawn/outline_spec.rb +408 -0
  179. data/spec/prawn/repeater_spec.rb +163 -0
  180. data/spec/prawn/soft_mask_spec.rb +72 -0
  181. data/spec/prawn/stamp_spec.rb +168 -0
  182. data/spec/prawn/text/box_spec.rb +1113 -0
  183. data/spec/prawn/text/formatted/arranger_spec.rb +464 -0
  184. data/spec/prawn/text/formatted/box_spec.rb +825 -0
  185. data/spec/prawn/text/formatted/fragment_spec.rb +341 -0
  186. data/spec/prawn/text/formatted/line_wrap_spec.rb +491 -0
  187. data/spec/prawn/text/formatted/parser_spec.rb +667 -0
  188. data/spec/prawn/text_draw_text_spec.rb +147 -0
  189. data/spec/prawn/text_rendering_mode_spec.rb +42 -0
  190. data/spec/prawn/text_spacing_spec.rb +93 -0
  191. data/spec/prawn/text_spec.rb +601 -0
  192. data/spec/prawn/text_with_inline_formatting_spec.rb +33 -0
  193. data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +21 -20
  194. data/spec/prawn/view_spec.rb +45 -0
  195. data/spec/spec_helper.rb +16 -16
  196. metadata +96 -151
  197. metadata.gz.sig +1 -0
  198. data/data/images/16bit.alpha +0 -0
  199. data/data/images/16bit.color +0 -0
  200. data/data/images/16bit.png +0 -0
  201. data/data/images/arrow.png +0 -0
  202. data/data/images/arrow2.png +0 -0
  203. data/data/images/blend_modes_bottom_layer.jpg +0 -0
  204. data/data/images/blend_modes_top_layer.jpg +0 -0
  205. data/data/images/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/indexed_transparency.png +0 -0
  213. data/data/images/indexed_transparency_alpha.dat +0 -0
  214. data/data/images/indexed_transparency_color.dat +0 -0
  215. data/data/images/letterhead.jpg +0 -0
  216. data/data/images/license.md +0 -8
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.color +0 -0
  219. data/data/images/page_white_text.png +0 -0
  220. data/data/images/pigs.jpg +0 -0
  221. data/data/images/prawn.png +0 -0
  222. data/data/images/ruport.png +0 -0
  223. data/data/images/ruport_data.dat +0 -0
  224. data/data/images/ruport_transparent.png +0 -0
  225. data/data/images/ruport_type0.png +0 -0
  226. data/data/images/stef.jpg +0 -0
  227. data/data/images/tru256.bmp +0 -0
  228. data/data/images/web-links.dat +0 -1
  229. data/data/images/web-links.png +0 -0
  230. data/data/pdfs/complex_template.pdf +0 -0
  231. data/data/pdfs/contains_ttf_font.pdf +0 -0
  232. data/data/pdfs/encrypted.pdf +0 -0
  233. data/data/pdfs/form.pdf +1 -819
  234. data/data/pdfs/hexagon.pdf +0 -61
  235. data/data/pdfs/indirect_reference.pdf +0 -86
  236. data/data/pdfs/multipage_template.pdf +0 -127
  237. data/data/pdfs/nested_pages.pdf +0 -118
  238. data/data/pdfs/page_without_mediabox.pdf +0 -193
  239. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  240. data/data/pdfs/two_hexagons.pdf +0 -90
  241. data/data/pdfs/version_1_6.pdf +0 -61
  242. data/data/shift_jis_text.txt +0 -1
  243. data/spec/acceptance/png_spec.rb +0 -35
  244. data/spec/annotations_spec.rb +0 -67
  245. data/spec/blend_mode_spec.rb +0 -71
  246. data/spec/bounding_box_spec.rb +0 -501
  247. data/spec/column_box_spec.rb +0 -59
  248. data/spec/destinations_spec.rb +0 -13
  249. data/spec/document_spec.rb +0 -738
  250. data/spec/font_metric_cache_spec.rb +0 -52
  251. data/spec/font_spec.rb +0 -475
  252. data/spec/formatted_text_arranger_spec.rb +0 -452
  253. data/spec/formatted_text_box_spec.rb +0 -716
  254. data/spec/formatted_text_fragment_spec.rb +0 -299
  255. data/spec/graphics_spec.rb +0 -705
  256. data/spec/grid_spec.rb +0 -95
  257. data/spec/images_spec.rb +0 -167
  258. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  259. data/spec/jpg_spec.rb +0 -23
  260. data/spec/line_wrap_spec.rb +0 -366
  261. data/spec/measurement_units_spec.rb +0 -22
  262. data/spec/outline_spec.rb +0 -409
  263. data/spec/png_spec.rb +0 -257
  264. data/spec/reference_spec.rb +0 -25
  265. data/spec/repeater_spec.rb +0 -154
  266. data/spec/security_spec.rb +0 -151
  267. data/spec/soft_mask_spec.rb +0 -78
  268. data/spec/span_spec.rb +0 -43
  269. data/spec/stamp_spec.rb +0 -179
  270. data/spec/stroke_styles_spec.rb +0 -208
  271. data/spec/text_at_spec.rb +0 -142
  272. data/spec/text_box_spec.rb +0 -1042
  273. data/spec/text_rendering_mode_spec.rb +0 -45
  274. data/spec/text_spacing_spec.rb +0 -93
  275. data/spec/text_spec.rb +0 -543
  276. data/spec/text_with_inline_formatting_spec.rb +0 -35
  277. data/spec/transparency_spec.rb +0 -91
  278. data/spec/view_spec.rb +0 -42
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
- #
3
1
  # blend_mode.rb : Implements blend modes
4
2
  #
5
3
  # Contributed by John Ford. October, 2015
@@ -15,9 +13,10 @@ module Prawn
15
13
  # Passing an array of blend modes is allowed. PDF viewers should
16
14
  # blend layers based on the first recognized blend mode.
17
15
  #
18
- # Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply, :Screen,
19
- # :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight, :SoftLight,
20
- # :Difference, :Exclusion, :Hue, :Saturation, :Color, and :Luminosity.
16
+ # Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply,
17
+ # :Screen, :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight,
18
+ # :SoftLight, :Difference, :Exclusion, :Hue, :Saturation, :Color, and
19
+ # :Luminosity.
21
20
  #
22
21
  # Example:
23
22
  # pdf.fill_color('0000ff')
@@ -52,11 +51,11 @@ module Prawn
52
51
  dictionary_name = "BM#{key}"
53
52
 
54
53
  dictionary = blend_mode_dictionary_registry[dictionary_name] ||= ref!(
55
- :Type => :ExtGState,
56
- :BM => blend_mode
54
+ Type: :ExtGState,
55
+ BM: blend_mode
57
56
  )
58
57
 
59
- page.ext_gstates.merge!(dictionary_name => dictionary)
58
+ page.ext_gstates[dictionary_name] = dictionary
60
59
  dictionary_name
61
60
  end
62
61
  end
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # cap_style.rb : Implements stroke cap styling
4
2
  #
5
3
  # Contributed by Daniel Nelson. October, 2009
@@ -11,7 +9,7 @@ module Prawn
11
9
  module CapStyle
12
10
  # @group Stable API
13
11
 
14
- CAP_STYLES = { :butt => 0, :round => 1, :projecting_square => 2 }
12
+ CAP_STYLES = { butt: 0, round: 1, projecting_square: 2 }.freeze
15
13
 
16
14
  # Sets the cap style for stroked lines and curves
17
15
  #
@@ -27,7 +25,7 @@ module Prawn
27
25
  write_stroke_cap_style
28
26
  end
29
27
 
30
- alias_method :cap_style=, :cap_style
28
+ alias cap_style= cap_style
31
29
 
32
30
  private
33
31
 
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # color.rb : Implements color handling
4
2
  #
5
3
  # Copyright June 2008, Gregory Brown. All Rights Reserved.
@@ -31,7 +29,7 @@ module Prawn
31
29
  set_fill_color
32
30
  end
33
31
 
34
- alias_method :fill_color=, :fill_color
32
+ alias fill_color= fill_color
35
33
 
36
34
  # Sets or returns the line stroking color.
37
35
  #
@@ -54,7 +52,7 @@ module Prawn
54
52
  set_stroke_color(color)
55
53
  end
56
54
 
57
- alias_method :stroke_color=, :stroke_color
55
+ alias stroke_color= stroke_color
58
56
 
59
57
  module_function
60
58
 
@@ -65,7 +63,7 @@ module Prawn
65
63
  # => "ff7808"
66
64
  #
67
65
  def rgb2hex(rgb)
68
- rgb.map { |e| "%02x" % e }.join
66
+ rgb.map { |e| format '%02x', e }.join
69
67
  end
70
68
 
71
69
  # Converts hex string into RGB value array:
@@ -74,27 +72,33 @@ module Prawn
74
72
  # => [255, 120, 8]
75
73
  #
76
74
  def hex2rgb(hex)
77
- r, g, b = hex[0..1], hex[2..3], hex[4..5]
75
+ r = hex[0..1]
76
+ g = hex[2..3]
77
+ b = hex[4..5]
78
78
  [r, g, b].map { |e| e.to_i(16) }
79
79
  end
80
80
 
81
81
  private
82
82
 
83
83
  def process_color(*color)
84
- case(color.size)
84
+ case color.size
85
85
  when 1
86
86
  color[0]
87
87
  when 4
88
88
  color
89
89
  else
90
- fail ArgumentError, 'wrong number of arguments supplied'
90
+ raise ArgumentError, 'wrong number of arguments supplied'
91
91
  end
92
92
  end
93
93
 
94
94
  def color_type(color)
95
95
  case color
96
96
  when String
97
- :RGB
97
+ if color =~ /\A[0-F]{6}\z/i
98
+ :RGB
99
+ else
100
+ raise ArgumentError, "Unknown type of color: #{color.inspect}"
101
+ end
98
102
  when Array
99
103
  case color.length
100
104
  when 3
@@ -102,7 +106,7 @@ module Prawn
102
106
  when 4
103
107
  :CMYK
104
108
  else
105
- fail ArgumentError, "Unknown type of color: #{color.inspect}"
109
+ raise ArgumentError, "Unknown type of color: #{color.inspect}"
106
110
  end
107
111
  end
108
112
  end
@@ -119,7 +123,7 @@ module Prawn
119
123
  end
120
124
 
121
125
  def color_to_s(color)
122
- normalize_color(color).map { |c| '%.3f' % c }.join(' ')
126
+ PDF::Core.real_params normalize_color(color)
123
127
  end
124
128
 
125
129
  def color_space(color)
@@ -131,15 +135,18 @@ module Prawn
131
135
  end
132
136
  end
133
137
 
134
- COLOR_SPACES = [:DeviceRGB, :DeviceCMYK, :Pattern]
138
+ COLOR_SPACES = [:DeviceRGB, :DeviceCMYK, :Pattern].freeze
135
139
 
136
140
  def set_color_space(type, color_space)
137
141
  # don't set the same color space again
138
- return if current_color_space(type) == color_space && !state.page.in_stamp_stream?
142
+ if current_color_space(type) == color_space &&
143
+ !state.page.in_stamp_stream?
144
+ return
145
+ end
139
146
  set_current_color_space(color_space, type)
140
147
 
141
148
  unless COLOR_SPACES.include?(color_space)
142
- fail ArgumentError, "unknown color space: '#{color_space}'"
149
+ raise ArgumentError, "unknown color space: '#{color_space}'"
143
150
  end
144
151
 
145
152
  operator = case type
@@ -148,7 +155,7 @@ module Prawn
148
155
  when :stroke
149
156
  'CS'
150
157
  else
151
- fail ArgumentError, "unknown type '#{type}'"
158
+ raise ArgumentError, "unknown type '#{type}'"
152
159
  end
153
160
 
154
161
  renderer.add_content "/#{color_space} #{operator}"
@@ -161,7 +168,7 @@ module Prawn
161
168
  when :stroke
162
169
  'SCN'
163
170
  else
164
- fail ArgumentError, "unknown type '#{type}'"
171
+ raise ArgumentError, "unknown type '#{type}'"
165
172
  end
166
173
 
167
174
  if options[:pattern]
@@ -187,8 +194,6 @@ module Prawn
187
194
  set_stroke_color
188
195
  end
189
196
 
190
- private
191
-
192
197
  def current_color_space(type)
193
198
  graphic_state.color_space[type]
194
199
  end
@@ -214,14 +219,6 @@ module Prawn
214
219
  graphic_state.stroke_color = color
215
220
  end
216
221
 
217
- def write_fill_color
218
- write_color(current_fill_color, 'scn')
219
- end
220
-
221
- def write_stroke_color
222
- write_color(current_fill_color, 'SCN')
223
- end
224
-
225
222
  def write_color(color, operator)
226
223
  renderer.add_content "#{color} #{operator}"
227
224
  end
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # dash.rb : Implements stroke dashing
4
2
  #
5
3
  # Contributed by Daniel Nelson. October, 2009
@@ -28,8 +26,9 @@ module Prawn
28
26
  # 3 on, 2 off, 3 on, 2 off, ...
29
27
  #
30
28
  # * If the parameter +length+ is an array, it specifies the
31
- # lengths of alternating dashes and gaps. The :space option is
32
- # ignored in this case.
29
+ # lengths of alternating dashes and gaps. The numbers must be
30
+ # non-negative and not all zero. The :space option is ignored
31
+ # in this case.
33
32
  #
34
33
  # Examples:
35
34
  #
@@ -37,6 +36,8 @@ module Prawn
37
36
  # 2 on, 1 off, 2 on, 1 off, ...
38
37
  # length = [3, 1, 2, 3]
39
38
  # 3 on, 1 off, 2 on, 3 off, 3 on, 1 off, ...
39
+ # length = [3, 0, 1]
40
+ # 3 on, 0 off, 1 on, 3 off, 0 on, 1 off, ...
40
41
  #
41
42
  # Options may contain the keys :space and :phase
42
43
  #
@@ -55,19 +56,28 @@ module Prawn
55
56
  def dash(length = nil, options = {})
56
57
  return current_dash_state if length.nil?
57
58
 
58
- if length == 0 || length.kind_of?(Array) && length.any? { |e| e == 0 }
59
- fail ArgumentError,
60
- "Zero length dashes are invalid. Call #undash to disable dashes."
59
+ length = Array(length)
60
+
61
+ if length.all?(&:zero?)
62
+ raise ArgumentError,
63
+ 'Zero length dashes are invalid. Call #undash to disable dashes.'
64
+ elsif length.any? { |e| e < 0 }
65
+ raise ArgumentError,
66
+ 'Negative numbers are not allowed for dash lengths.'
61
67
  end
62
68
 
63
- self.current_dash_state = { :dash => length,
64
- :space => length.kind_of?(Array) ? nil : options[:space] || length,
65
- :phase => options[:phase] || 0 }
69
+ length = length.first if length.length == 1
70
+
71
+ self.current_dash_state = {
72
+ dash: length,
73
+ space: length.is_a?(Array) ? nil : options[:space] || length,
74
+ phase: options[:phase] || 0
75
+ }
66
76
 
67
77
  write_stroke_dash
68
78
  end
69
79
 
70
- alias_method :dash=, :dash
80
+ alias dash= dash
71
81
 
72
82
  # Stops dashing, restoring solid stroked lines and curves
73
83
  #
@@ -89,7 +99,7 @@ module Prawn
89
99
  end
90
100
 
91
101
  def undashed_setting
92
- { :dash => nil, :space => nil, :phase => 0 }
102
+ { dash: nil, space: nil, phase: 0 }
93
103
  end
94
104
 
95
105
  def current_dash_state=(dash_options)
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  # join_style.rb : Implements stroke join styling
4
2
  #
5
3
  # Contributed by Daniel Nelson. October, 2009
@@ -9,7 +7,7 @@
9
7
  module Prawn
10
8
  module Graphics
11
9
  module JoinStyle
12
- JOIN_STYLES = { :miter => 0, :round => 1, :bevel => 2 }
10
+ JOIN_STYLES = { miter: 0, round: 1, bevel: 2 }.freeze
13
11
 
14
12
  # @group Stable API
15
13
 
@@ -25,10 +23,16 @@ module Prawn
25
23
 
26
24
  self.current_join_style = style
27
25
 
26
+ unless JOIN_STYLES.key?(current_join_style)
27
+ raise Prawn::Errors::InvalidJoinStyle,
28
+ "#{style} is not a recognized join style. Valid styles are " +
29
+ JOIN_STYLES.keys.join(', ')
30
+ end
31
+
28
32
  write_stroke_join_style
29
33
  end
30
34
 
31
- alias_method :join_style=, :join_style
35
+ alias join_style= join_style
32
36
 
33
37
  private
34
38
 
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ require 'digest/sha1'
2
2
 
3
3
  # patterns.rb : Implements axial & radial gradients
4
4
  #
@@ -10,52 +10,83 @@
10
10
  module Prawn
11
11
  module Graphics
12
12
  module Patterns
13
+ GradientStop = Struct.new(:position, :color)
14
+ Gradient = Struct.new(
15
+ :type, :apply_transformations, :stops, :from, :to, :r1, :r2
16
+ )
17
+
13
18
  # @group Stable API
14
19
 
15
- # Sets the fill gradient from color1 to color2.
16
- # old arguments: point, width, height, color1, color2, options = {}
17
- # new arguments: from, to, color1, color1, options = {}
18
- # or from, r1, to, r2, color1, color2, options = {}
20
+ # Sets the fill gradient.
21
+ # old arguments:
22
+ # from, to, color1, color2
23
+ # or
24
+ # from, r1, to, r2, color1, color2
25
+ # new arguments:
26
+ # from: [x, y]
27
+ # to: [x, y]
28
+ # r1: radius
29
+ # r2: radius
30
+ # stops: [color, color, ...] or
31
+ # { position => color, position => color, ... }
32
+ # apply_transformations: true
33
+ #
34
+ # Examples:
35
+ #
36
+ # # draws a horizontal axial gradient that starts at red on the left
37
+ # # and ends at blue on the right
38
+ # fill_gradient from: [0, 0], to: [100, 0], stops: ['red', 'blue']
39
+ #
40
+ # # draws a horizontal radial gradient that starts at red, is green
41
+ # # 80% of the way through, and finishes blue
42
+ # fill_gradient from: [0, 0], r1: 0, to: [100, 0], r2: 180,
43
+ # stops: { 0 => 'red', 0.8 => 'green', 1 => 'blue' }
44
+ #
45
+ # <tt>from</tt> and <tt>to</tt> specify the axis of where the gradient
46
+ # should be painted.
19
47
  #
20
- # Option :apply_transformations, if set true, will transform the
48
+ # <tt>r1</tt> and <tt>r2</tt>, if specified, make a radial gradient with
49
+ # the starting circle of radius <tt>r1</tt> centered at <tt>from</tt>
50
+ # and ending at a circle of radius <tt>r2</tt> centered at <tt>to</tt>.
51
+ # If <tt>r1</tt> is not specified, a axial gradient will be drawn.
52
+ #
53
+ # <tt>stops</tt> is an array or hash of stops. Each stop is either just a
54
+ # string indicating the color, in which case the stops will be evenly
55
+ # distributed across the gradient, or a hash where the key is
56
+ # a position between 0 and 1 indicating what distance through the
57
+ # gradient the color should change, and the value is a color string.
58
+ #
59
+ # Option <tt>apply_transformations</tt>, if set true, will transform the
21
60
  # gradient's co-ordinate space so it matches the current co-ordinate
22
- # space of the document. This option will be the default from Prawn v3.
23
- # The current default, false, will mean if you (for example) scale your
24
- # document by 2 and put a gradient inside, you will have to manually
25
- # multiply your co-ordinates by 2 so the gradient is correctly positioned.
26
- def fill_gradient(*args)
27
- set_gradient(:fill, *args)
61
+ # space of the document. This option will be the default from Prawn v3,
62
+ # and is default true if you use the new arguments format.
63
+ # The default for the old arguments format, false, will mean if you
64
+ # (for example) scale your document by 2 and put a gradient inside, you
65
+ # will have to manually multiply your co-ordinates by 2 so the gradient
66
+ # is correctly positioned.
67
+ def fill_gradient(*args, **kwargs)
68
+ set_gradient(:fill, *args, **kwargs)
28
69
  end
29
70
 
30
- # Sets the stroke gradient from color1 to color2.
31
- # old arguments: point, width, height, color1, color2, options = {}
32
- # new arguments: from, to, color1, color2, options = {}
33
- # or from, r1, to, r2, color1, color2, options = {}
34
- #
35
- # Option :apply_transformations, if set true, will transform the
36
- # gradient's co-ordinate space so it matches the current co-ordinate
37
- # space of the document. This option will be the default from Prawn v3.
38
- # The current default, false, will mean if you (for example) scale your
39
- # document by 2 and put a gradient inside, you will have to manually
40
- # multiply your co-ordinates by 2 so the gradient is correctly positioned.
41
- def stroke_gradient(*args)
42
- set_gradient(:stroke, *args)
71
+ # Sets the stroke gradient.
72
+ # See fill_gradient for a description of the arguments to this method.
73
+ def stroke_gradient(*args, **kwargs)
74
+ set_gradient(:stroke, *args, **kwargs)
43
75
  end
44
76
 
45
77
  private
46
78
 
47
- def set_gradient(type, *grad)
48
- opts = grad.last.is_a?(Hash) ? grad.pop : {}
79
+ def set_gradient(type, *grad, **kwargs)
80
+ gradient = parse_gradient_arguments(*grad, **kwargs)
49
81
 
50
82
  patterns = page.resources[:Pattern] ||= {}
51
83
 
52
- registry_key = gradient_registry_key grad, opts
84
+ registry_key = gradient_registry_key gradient
53
85
 
54
- if patterns["SP#{registry_key}"]
55
- shading = patterns["SP#{registry_key}"]
56
- else
57
- unless shading = gradient_registry[registry_key]
58
- shading = gradient(grad, opts)
86
+ unless patterns.key? "SP#{registry_key}"
87
+ shading = gradient_registry[registry_key]
88
+ unless shading
89
+ shading = create_gradient_pattern(gradient)
59
90
  gradient_registry[registry_key] = shading
60
91
  end
61
92
 
@@ -68,96 +99,154 @@ module Prawn
68
99
  when :stroke
69
100
  'SCN'
70
101
  else
71
- fail ArgumentError, "unknown type '#{type}'"
102
+ raise ArgumentError, "unknown type '#{type}'"
72
103
  end
73
104
 
74
105
  set_color_space type, :Pattern
75
106
  renderer.add_content "/SP#{registry_key} #{operator}"
76
107
  end
77
108
 
78
- def gradient_registry_key(gradient, opts)
79
- _x1, _y1, x2, y2, transformation = gradient_coordinates(gradient, opts)
80
-
81
- if gradient[1].is_a?(Array) # axial
82
- [
83
- transformation,
84
- x2, y2,
85
- gradient[2], gradient[3]
86
- ]
87
- else # radial
88
- [
89
- transformation,
90
- x2, y2,
91
- gradient[1],
92
- gradient[3],
93
- gradient[4], gradient[5]
94
- ]
95
- end.hash
96
- end
97
-
98
- def gradient_registry
99
- @gradient_registry ||= {}
100
- end
101
-
102
- def gradient(args, opts)
103
- if args.length != 4 && args.length != 6
104
- fail ArgumentError, "Unknown type of gradient: #{args.inspect}"
109
+ def parse_gradient_arguments( # rubocop: disable Metrics/ParameterLists
110
+ *arguments, from: nil, to: nil, r1: nil, r2: nil, stops: nil,
111
+ apply_transformations: nil
112
+ )
113
+ case arguments.length
114
+ when 0
115
+ apply_transformations = true if apply_transformations.nil?
116
+ when 4
117
+ from, to, *stops = arguments
118
+ when 6
119
+ from, r1, to, r2, *stops = arguments
120
+ else
121
+ raise ArgumentError, "Unknown type of gradient: #{arguments.inspect}"
105
122
  end
106
123
 
107
- if opts[:apply_transformations].nil? && current_transformation_matrix_with_translation(0, 0) != [1, 0, 0, 1, 0, 0]
108
- warn "Gradients in Prawn 2.x and lower are not correctly positioned when a transformation has been made to the document. Pass 'apply_transformations: true' to correctly transform the gradient, or see https://github.com/prawnpdf/prawn/wiki/Gradient-Transformations for more information."
124
+ if stops.length < 2
125
+ raise ArgumentError, 'At least two stops must be specified'
109
126
  end
110
127
 
111
- color1 = normalize_color(args[-2]).dup.freeze
112
- color2 = normalize_color(args[-1]).dup.freeze
128
+ stops = stops.map.with_index do |stop, index|
129
+ case stop
130
+ when Array, Hash
131
+ position, color = stop
132
+ else
133
+ position = index / (stops.length.to_f - 1)
134
+ color = stop
135
+ end
113
136
 
114
- if color_type(color1) != color_type(color2)
115
- fail ArgumentError, "Both colors must be of the same color space: #{color1.inspect} and #{color2.inspect}"
137
+ unless (0..1).cover?(position)
138
+ raise ArgumentError, 'position must be between 0 and 1'
139
+ end
140
+ GradientStop.new(position, normalize_color(color))
116
141
  end
117
142
 
118
- process_color color1
119
- process_color color2
143
+ if stops.first.position != 0
144
+ raise ArgumentError, 'The first stop must have a position of 0'
145
+ end
146
+ if stops.last.position != 1
147
+ raise ArgumentError, 'The last stop must have a position of 1'
148
+ end
120
149
 
121
- shader = ref!(
122
- :FunctionType => 2,
123
- :Domain => [0.0, 1.0],
124
- :C0 => color1,
125
- :C1 => color2,
126
- :N => 1.0
150
+ if stops.map { |stop| color_type(stop.color) }.uniq.length > 1
151
+ raise ArgumentError, 'All colors must be of the same color space'
152
+ end
153
+
154
+ Gradient.new(
155
+ r1 ? :radial : :axial,
156
+ apply_transformations,
157
+ stops,
158
+ from, to,
159
+ r1, r2
127
160
  )
161
+ end
128
162
 
129
- x1, y1, x2, y2, transformation = gradient_coordinates(args, opts)
163
+ def gradient_registry_key(gradient)
164
+ _x1, _y1, x2, y2, transformation = gradient_coordinates(gradient)
165
+
166
+ key = [
167
+ gradient.type.to_s,
168
+ transformation,
169
+ x2, y2,
170
+ gradient.r1 || -1, gradient.r2 || -1,
171
+ gradient.stops.length,
172
+ gradient.stops.map { |s| [s.position, s.color] }
173
+ ].flatten
174
+ Digest::SHA1.hexdigest(key.pack('HC*'))
175
+ end
130
176
 
131
- if args.length == 4
132
- coords = [0, 0, x2 - x1, y2 - y1]
133
- else
134
- coords = [0, 0, args[1], x2 - x1, y2 - y1, args[3]]
177
+ def gradient_registry
178
+ @gradient_registry ||= {}
179
+ end
180
+
181
+ def create_gradient_pattern(gradient)
182
+ if gradient.apply_transformations.nil? &&
183
+ current_transformation_matrix_with_translation(0, 0) !=
184
+ [1, 0, 0, 1, 0, 0]
185
+ warn 'Gradients in Prawn 2.x and lower are not correctly positioned '\
186
+ 'when a transformation has been made to the document. ' \
187
+ "Pass 'apply_transformations: true' to correctly transform the " \
188
+ 'gradient, or see ' \
189
+ 'https://github.com/prawnpdf/prawn/wiki/Gradient-Transformations ' \
190
+ 'for more information.'
135
191
  end
136
192
 
193
+ shader_stops = gradient.stops.each_cons(2).map do |first, second|
194
+ ref!(
195
+ FunctionType: 2,
196
+ Domain: [0.0, 1.0],
197
+ C0: first.color,
198
+ C1: second.color,
199
+ N: 1.0
200
+ )
201
+ end
202
+
203
+ # If there's only two stops, we can use the single shader.
204
+ # Otherwise we stitch the multiple shaders together.
205
+ shader = if shader_stops.length == 1
206
+ shader_stops.first
207
+ else
208
+ ref!(
209
+ FunctionType: 3, # stitching function
210
+ Domain: [0.0, 1.0],
211
+ Functions: shader_stops,
212
+ Bounds: gradient.stops[1..-2].map(&:position),
213
+ Encode: [0.0, 1.0] * shader_stops.length
214
+ )
215
+ end
216
+
217
+ x1, y1, x2, y2, transformation = gradient_coordinates(gradient)
218
+
219
+ coords = if gradient.type == :axial
220
+ [0, 0, x2 - x1, y2 - y1]
221
+ else
222
+ [0, 0, gradient.r1, x2 - x1, y2 - y1, gradient.r2]
223
+ end
224
+
137
225
  shading = ref!(
138
- :ShadingType => args.length == 4 ? 2 : 3, # axial : radial shading
139
- :ColorSpace => color_space(color1),
140
- :Coords => coords,
141
- :Function => shader,
142
- :Extend => [true, true]
226
+ ShadingType: gradient.type == :axial ? 2 : 3,
227
+ ColorSpace: color_space(gradient.stops.first.color),
228
+ Coords: coords,
229
+ Function: shader,
230
+ Extend: [true, true]
143
231
  )
144
232
 
145
233
  ref!(
146
- :PatternType => 2, # shading pattern
147
- :Shading => shading,
148
- :Matrix => transformation
234
+ PatternType: 2, # shading pattern
235
+ Shading: shading,
236
+ Matrix: transformation
149
237
  )
150
238
  end
151
239
 
152
- def gradient_coordinates(args, opts)
153
- x1, y1 = map_to_absolute(args[0])
154
- x2, y2 = map_to_absolute(args[args.length == 4 ? 1 : 2])
240
+ def gradient_coordinates(gradient)
241
+ x1, y1 = map_to_absolute(gradient.from)
242
+ x2, y2 = map_to_absolute(gradient.to)
155
243
 
156
- transformation = if opts[:apply_transformations]
157
- current_transformation_matrix_with_translation(x1, y1)
158
- else
159
- [1, 0, 0, 1, x1, y1]
160
- end
244
+ transformation =
245
+ if gradient.apply_transformations
246
+ current_transformation_matrix_with_translation(x1, y1)
247
+ else
248
+ [1, 0, 0, 1, x1, y1]
249
+ end
161
250
 
162
251
  [x1, y1, x2, y2, transformation]
163
252
  end