prawn 1.0.0.rc1 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/Gemfile +18 -0
  2. data/README.md +5 -3
  3. data/Rakefile +8 -14
  4. data/data/pdfs/nested_pages.pdf +13 -13
  5. data/lib/prawn.rb +3 -1
  6. data/lib/prawn/compatibility.rb +46 -10
  7. data/lib/prawn/core.rb +3 -1
  8. data/lib/prawn/core/document_state.rb +2 -1
  9. data/lib/prawn/core/object_store.rb +61 -5
  10. data/lib/prawn/core/page.rb +3 -6
  11. data/lib/prawn/core/pdf_object.rb +21 -4
  12. data/lib/prawn/core/reference.rb +6 -2
  13. data/lib/prawn/core/text.rb +4 -4
  14. data/lib/prawn/core/text/formatted/line_wrap.rb +23 -8
  15. data/lib/prawn/document.rb +21 -15
  16. data/lib/prawn/document/bounding_box.rb +3 -3
  17. data/lib/prawn/document/column_box.rb +22 -4
  18. data/lib/prawn/document/snapshot.rb +1 -1
  19. data/lib/prawn/encoding.rb +1 -1
  20. data/lib/prawn/errors.rb +4 -0
  21. data/lib/prawn/font.rb +1 -1
  22. data/lib/prawn/font/afm.rb +30 -72
  23. data/lib/prawn/font/ttf.rb +6 -33
  24. data/lib/prawn/graphics.rb +148 -23
  25. data/lib/prawn/graphics/color.rb +8 -1
  26. data/lib/prawn/graphics/patterns.rb +137 -0
  27. data/lib/prawn/images.rb +25 -19
  28. data/lib/prawn/images/jpg.rb +4 -4
  29. data/lib/prawn/images/png.rb +18 -12
  30. data/lib/prawn/security.rb +6 -4
  31. data/lib/prawn/soft_mask.rb +94 -0
  32. data/lib/prawn/table.rb +136 -31
  33. data/lib/prawn/table/cell.rb +260 -29
  34. data/lib/prawn/table/cell/span_dummy.rb +88 -0
  35. data/lib/prawn/table/cell/text.rb +36 -14
  36. data/lib/prawn/table/cells.rb +91 -41
  37. data/lib/prawn/text.rb +3 -2
  38. data/lib/prawn/text/formatted/box.rb +14 -5
  39. data/lib/prawn/text/formatted/fragment.rb +33 -22
  40. data/lib/prawn/text/formatted/parser.rb +5 -2
  41. data/lib/prawn/utilities.rb +44 -0
  42. data/manual/basic_concepts/adding_pages.rb +27 -0
  43. data/manual/basic_concepts/basic_concepts.rb +34 -0
  44. data/manual/basic_concepts/creation.rb +39 -0
  45. data/manual/basic_concepts/cursor.rb +33 -0
  46. data/manual/basic_concepts/measurement.rb +25 -0
  47. data/manual/basic_concepts/origin.rb +38 -0
  48. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  49. data/manual/bounding_box/bounding_box.rb +39 -0
  50. data/manual/bounding_box/bounds.rb +49 -0
  51. data/manual/bounding_box/canvas.rb +24 -0
  52. data/manual/bounding_box/creation.rb +23 -0
  53. data/manual/bounding_box/indentation.rb +46 -0
  54. data/manual/bounding_box/nesting.rb +45 -0
  55. data/manual/bounding_box/russian_boxes.rb +40 -0
  56. data/manual/bounding_box/stretchy.rb +31 -0
  57. data/manual/document_and_page_options/background.rb +27 -0
  58. data/manual/document_and_page_options/document_and_page_options.rb +31 -0
  59. data/manual/document_and_page_options/metadata.rb +23 -0
  60. data/manual/document_and_page_options/page_margins.rb +38 -0
  61. data/manual/document_and_page_options/page_size.rb +34 -0
  62. data/manual/example_file.rb +116 -0
  63. data/manual/example_helper.rb +430 -0
  64. data/manual/example_package.rb +53 -0
  65. data/manual/example_section.rb +46 -0
  66. data/manual/graphics/circle_and_ellipse.rb +22 -0
  67. data/manual/graphics/color.rb +24 -0
  68. data/manual/graphics/common_lines.rb +28 -0
  69. data/manual/graphics/fill_and_stroke.rb +42 -0
  70. data/manual/graphics/fill_rules.rb +37 -0
  71. data/manual/graphics/gradients.rb +37 -0
  72. data/manual/graphics/graphics.rb +58 -0
  73. data/manual/graphics/helper.rb +17 -0
  74. data/manual/graphics/line_width.rb +35 -0
  75. data/manual/graphics/lines_and_curves.rb +41 -0
  76. data/manual/graphics/polygon.rb +29 -0
  77. data/manual/graphics/rectangle.rb +21 -0
  78. data/manual/graphics/rotate.rb +28 -0
  79. data/manual/graphics/scale.rb +41 -0
  80. data/manual/graphics/soft_masks.rb +46 -0
  81. data/manual/graphics/stroke_cap.rb +31 -0
  82. data/manual/graphics/stroke_dash.rb +43 -0
  83. data/manual/graphics/stroke_join.rb +30 -0
  84. data/manual/graphics/translate.rb +29 -0
  85. data/manual/graphics/transparency.rb +35 -0
  86. data/manual/images/absolute_position.rb +23 -0
  87. data/manual/images/fit.rb +21 -0
  88. data/manual/images/horizontal.rb +25 -0
  89. data/manual/images/images.rb +40 -0
  90. data/manual/images/plain_image.rb +18 -0
  91. data/manual/images/scale.rb +22 -0
  92. data/manual/images/vertical.rb +28 -0
  93. data/manual/images/width_and_height.rb +25 -0
  94. data/manual/layout/boxes.rb +27 -0
  95. data/manual/layout/content.rb +25 -0
  96. data/manual/layout/layout.rb +28 -0
  97. data/manual/layout/simple_grid.rb +23 -0
  98. data/manual/manual/cover.rb +26 -0
  99. data/manual/manual/foreword.rb +13 -0
  100. data/manual/manual/how_to_read_this_manual.rb +41 -0
  101. data/manual/manual/manual.rb +36 -0
  102. data/manual/outline/add_subsection_to.rb +61 -0
  103. data/manual/outline/insert_section_after.rb +47 -0
  104. data/manual/outline/outline.rb +32 -0
  105. data/manual/outline/sections_and_pages.rb +67 -0
  106. data/manual/repeatable_content/page_numbering.rb +54 -0
  107. data/manual/repeatable_content/repeatable_content.rb +31 -0
  108. data/manual/repeatable_content/repeater.rb +55 -0
  109. data/manual/repeatable_content/stamp.rb +41 -0
  110. data/manual/security/encryption.rb +31 -0
  111. data/manual/security/permissions.rb +38 -0
  112. data/manual/security/security.rb +28 -0
  113. data/manual/syntax_highlight.rb +52 -0
  114. data/manual/table/basic_block.rb +53 -0
  115. data/manual/table/before_rendering_page.rb +26 -0
  116. data/manual/table/cell_border_lines.rb +24 -0
  117. data/manual/table/cell_borders_and_bg.rb +31 -0
  118. data/manual/table/cell_dimensions.rb +30 -0
  119. data/manual/table/cell_text.rb +38 -0
  120. data/manual/table/column_widths.rb +30 -0
  121. data/manual/table/content_and_subtables.rb +39 -0
  122. data/manual/table/creation.rb +27 -0
  123. data/manual/table/filtering.rb +36 -0
  124. data/manual/table/flow_and_header.rb +17 -0
  125. data/manual/table/image_cells.rb +33 -0
  126. data/manual/table/position.rb +29 -0
  127. data/manual/table/row_colors.rb +20 -0
  128. data/manual/table/span.rb +30 -0
  129. data/manual/table/style.rb +22 -0
  130. data/manual/table/table.rb +52 -0
  131. data/manual/table/width.rb +27 -0
  132. data/manual/templates/full_template.rb +23 -0
  133. data/manual/templates/page_template.rb +47 -0
  134. data/manual/templates/templates.rb +26 -0
  135. data/manual/text/alignment.rb +44 -0
  136. data/manual/text/color.rb +24 -0
  137. data/manual/text/column_box.rb +32 -0
  138. data/manual/text/fallback_fonts.rb +37 -0
  139. data/manual/text/font.rb +41 -0
  140. data/manual/text/font_size.rb +45 -0
  141. data/manual/text/font_style.rb +23 -0
  142. data/manual/text/formatted_callbacks.rb +60 -0
  143. data/manual/text/formatted_text.rb +50 -0
  144. data/manual/text/free_flowing_text.rb +51 -0
  145. data/manual/text/group.rb +29 -0
  146. data/manual/text/inline.rb +43 -0
  147. data/manual/text/kerning_and_character_spacing.rb +39 -0
  148. data/manual/text/leading.rb +25 -0
  149. data/manual/text/line_wrapping.rb +41 -0
  150. data/manual/text/paragraph_indentation.rb +26 -0
  151. data/manual/text/positioned_text.rb +38 -0
  152. data/manual/text/registering_families.rb +48 -0
  153. data/manual/text/rendering_and_color.rb +37 -0
  154. data/manual/text/right_to_left_text.rb +43 -0
  155. data/manual/text/rotation.rb +43 -0
  156. data/manual/text/single_usage.rb +37 -0
  157. data/manual/text/text.rb +75 -0
  158. data/manual/text/text_box_excess.rb +32 -0
  159. data/manual/text/text_box_extensions.rb +45 -0
  160. data/manual/text/text_box_overflow.rb +44 -0
  161. data/manual/text/utf8.rb +28 -0
  162. data/manual/text/win_ansi_charset.rb +59 -0
  163. data/prawn.gemspec +10 -7
  164. data/spec/bounding_box_spec.rb +107 -17
  165. data/spec/cell_spec.rb +66 -40
  166. data/spec/column_box_spec.rb +33 -0
  167. data/spec/document_spec.rb +45 -24
  168. data/spec/extensions/encoding_helpers.rb +6 -0
  169. data/spec/extensions/mocha.rb +1 -0
  170. data/spec/font_spec.rb +71 -53
  171. data/spec/formatted_text_arranger_spec.rb +19 -19
  172. data/spec/formatted_text_box_spec.rb +16 -16
  173. data/spec/formatted_text_fragment_spec.rb +6 -6
  174. data/spec/graphics_spec.rb +96 -31
  175. data/spec/grid_spec.rb +2 -2
  176. data/spec/images_spec.rb +18 -10
  177. data/spec/jpg_spec.rb +1 -1
  178. data/spec/line_wrap_spec.rb +14 -14
  179. data/spec/measurement_units_spec.rb +2 -2
  180. data/spec/name_tree_spec.rb +6 -6
  181. data/spec/object_store_spec.rb +17 -17
  182. data/spec/outline_spec.rb +35 -17
  183. data/spec/pdf_object_spec.rb +3 -1
  184. data/spec/png_spec.rb +22 -19
  185. data/spec/reference_spec.rb +24 -1
  186. data/spec/repeater_spec.rb +9 -9
  187. data/spec/security_spec.rb +3 -3
  188. data/spec/snapshot_spec.rb +3 -3
  189. data/spec/soft_mask_spec.rb +117 -0
  190. data/spec/span_spec.rb +4 -4
  191. data/spec/spec_helper.rb +12 -6
  192. data/spec/stamp_spec.rb +12 -12
  193. data/spec/stroke_styles_spec.rb +5 -5
  194. data/spec/table_spec.rb +458 -88
  195. data/spec/template_spec.rb +108 -54
  196. data/spec/text_at_spec.rb +17 -17
  197. data/spec/text_box_spec.rb +76 -45
  198. data/spec/text_rendering_mode_spec.rb +5 -5
  199. data/spec/text_spacing_spec.rb +4 -4
  200. data/spec/text_spec.rb +44 -40
  201. metadata +419 -250
  202. data/lib/prawn/graphics/gradient.rb +0 -84
  203. data/lib/prawn/security/arcfour.rb +0 -51
@@ -47,7 +47,7 @@ module Prawn
47
47
  end
48
48
  end * scale
49
49
  else
50
- string.unpack("U*").inject(0) do |s,r|
50
+ string.codepoints.inject(0) do |s,r|
51
51
  s + character_width_by_code(r)
52
52
  end * scale
53
53
  end
@@ -160,44 +160,18 @@ module Prawn
160
160
  end
161
161
 
162
162
  def normalize_encoding(text)
163
- if text.respond_to?(:encode)
164
- # if we're running under a M17n aware VM, ensure the string provided is
165
- # UTF-8 (by converting it if necessary)
166
- begin
167
- text.encode("UTF-8")
168
- rescue
169
- raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
170
- "#{text.encoding} can not be transparently converted to UTF-8. " +
171
- "Please ensure the encoding of the string you are attempting " +
172
- "to use is set correctly"
173
- end
174
- else
175
- # on a non M17N aware VM, use unpack as a hackish way to verify the
176
- # string is valid utf-8. I thought it was better than loading iconv
177
- # though.
178
- begin
179
- text.unpack("U*")
180
- return text.dup
181
- rescue
182
- raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
183
- "are attempting to render is not encoded in valid UTF-8."
184
- end
185
- end
163
+ text.normalize_to_utf8
186
164
  end
187
165
 
188
166
  def glyph_present?(char)
189
- code = char.unpack("U*").first
167
+ code = char.codepoints.first
190
168
  cmap[code] > 0
191
169
  end
192
170
 
193
171
  # Returns the number of characters in +str+ (a UTF-8-encoded string).
194
172
  #
195
173
  def character_count(str)
196
- if str.respond_to?(:encode)
197
- str.length
198
- else
199
- str.unpack("U*").length
200
- end
174
+ str.unicode_length
201
175
  end
202
176
 
203
177
  private
@@ -214,7 +188,7 @@ module Prawn
214
188
  def kern(string)
215
189
  a = []
216
190
 
217
- string.unpack("U*").each do |r|
191
+ string.codepoints do |r|
218
192
  if a.empty?
219
193
  a << [r]
220
194
  elsif (kern = kern_pairs_table[[cmap[a.last.last], cmap[r]]])
@@ -282,8 +256,7 @@ module Prawn
282
256
 
283
257
  compressed_font = Zlib::Deflate.deflate(font_content)
284
258
 
285
- fontfile = @document.ref!(:Length => compressed_font.size,
286
- :Length1 => font_content.size,
259
+ fontfile = @document.ref!(:Length1 => font_content.size,
287
260
  :Filter => :FlateDecode )
288
261
  fontfile << compressed_font
289
262
 
@@ -12,7 +12,7 @@ require "prawn/graphics/cap_style"
12
12
  require "prawn/graphics/join_style"
13
13
  require "prawn/graphics/transparency"
14
14
  require "prawn/graphics/transformation"
15
- require "prawn/graphics/gradient"
15
+ require "prawn/graphics/patterns"
16
16
 
17
17
  module Prawn
18
18
 
@@ -30,7 +30,7 @@ module Prawn
30
30
  include JoinStyle
31
31
  include Transparency
32
32
  include Transformation
33
- include Gradient
33
+ include Patterns
34
34
 
35
35
  #######################################################################
36
36
  # Low level drawing operations must map the point to absolute coords! #
@@ -222,19 +222,19 @@ module Prawn
222
222
 
223
223
  # Upper right hand corner
224
224
  curve_to [x, y + r2],
225
- :bounds => [[x + r1, y + l1], [x + l2, y + r2]]
225
+ :bounds => [[x + r1, y + l2], [x + l1, y + r2]]
226
226
 
227
227
  # Upper left hand corner
228
228
  curve_to [x - r1, y],
229
- :bounds => [[x - l2, y + r2], [x - r1, y + l1]]
229
+ :bounds => [[x - l1, y + r2], [x - r1, y + l2]]
230
230
 
231
231
  # Lower left hand corner
232
232
  curve_to [x, y - r2],
233
- :bounds => [[x - r1, y - l1], [x - l2, y - r2]]
233
+ :bounds => [[x - r1, y - l2], [x - l1, y - r2]]
234
234
 
235
235
  # Lower right hand corner
236
236
  curve_to [x + r1, y],
237
- :bounds => [[x + l2, y - r2], [x + r1, y - l1]]
237
+ :bounds => [[x + l1, y - r2], [x + r1, y - l2]]
238
238
 
239
239
  move_to(x, y)
240
240
  end
@@ -337,23 +337,148 @@ module Prawn
337
337
  add_content "h"
338
338
  end
339
339
 
340
- # Provides the following shortcuts:
341
- #
342
- # stroke_some_method(*args) #=> some_method(*args); stroke
343
- # fill_some_method(*args) #=> some_method(*args); fill
344
- # fill_and_stroke_some_method(*args) #=> some_method(*args); fill_and_stroke
345
- #
346
- def method_missing(id,*args,&block)
347
- case(id.to_s)
348
- when /^fill_and_stroke_(.*)/
349
- send($1,*args,&block); fill_and_stroke
350
- when /^stroke_(.*)/
351
- send($1,*args,&block); stroke
352
- when /^fill_(.*)/
353
- send($1,*args,&block); fill
354
- else
355
- super
356
- end
340
+ ##
341
+ # :method: stroke_rectangle
342
+ # Draws and strokes a rectangle given +point+, +width+ and +height+. The rectangle is bounded by its upper-left corner.
343
+ # :call-seq:
344
+ # stroke_rectangle(point,width,height)
345
+
346
+ ##
347
+ # :method: fill_rectangle
348
+ # Draws and fills ills a rectangle given +point+, +width+ and +height+. The rectangle is bounded by its upper-left corner.
349
+ # :call-seq:
350
+ # fill_rectangle(point,width,height)
351
+
352
+ ##
353
+ # :method: fill_and_stroke_rectangle
354
+ # Draws, fills, and strokes a rectangle given +point+, +width+ and +height+. The rectangle is bounded by its upper-left corner.
355
+ # :call-seq:
356
+ # fill_and_stroke_rectangle(point,width,height)
357
+
358
+ ##
359
+ # :method: stroke_rounded_rectangle
360
+ # Draws and strokes a rounded rectangle given +point+, +width+ and +height+ and +radius+ for the rounded corner. The rectangle is bounded by its upper-left corner.
361
+ # :call-seq:
362
+ # stroke_rounded_rectangle(point,width,height,radius)
363
+
364
+ ##
365
+ # :method: fill_rounded_rectangle
366
+ # Draws and fills a rounded rectangle given +point+, +width+ and +height+ and +radius+ for the rounded corner. The rectangle is bounded by its upper-left corner.
367
+ # :call-seq:
368
+ # fill_rounded_rectangle(point,width,height,radius)
369
+
370
+ ##
371
+ # :method: stroke_and_fill_rounded_rectangle
372
+ # Draws, fills, and strokes a rounded rectangle given +point+, +width+ and +height+ and +radius+ for the rounded corner. The rectangle is bounded by its upper-left corner.
373
+ # :call-seq:
374
+ # stroke_and_fill_rounded_rectangle(point,width,height,radius)
375
+
376
+ ##
377
+ # :method: stroke_line
378
+ # Strokes a line from one point to another. Points may be specified as tuples or flattened argument list.
379
+ # :call-seq:
380
+ # stroke_line(*points)
381
+
382
+ ##
383
+ # :method: stroke_horizontal_line
384
+ # Strokes a horizontal line from +x1+ to +x2+ at the current y position, or the position specified by the :at option.
385
+ # :call-seq:
386
+ # stroke_horizontal_line(x1,x2,options={})
387
+
388
+ ##
389
+ # :method: stroke_horizontal_rule
390
+ # Strokes a horizontal line from the left border to the right border of the bounding box at the current y position.
391
+
392
+ ##
393
+ # :method: stroke_vertical_line
394
+ # Strokes a vertical line at the x coordinate given by :at from y1 to y2.
395
+ # :call-seq:
396
+ # stroke_vertical_line(y1,y2,params)
397
+
398
+ ##
399
+ # :method: stroke_curve
400
+ # Strokes a Bezier curve between two points, bounded by two additional points.
401
+ # :call-seq:
402
+ # stroke_curve(origin,dest,options={})
403
+
404
+ ##
405
+ # :method: stroke_circle
406
+ # Draws and strokes a circle of radius +radius+ with the centre-point at +point+.
407
+ # :call-seq:
408
+ # stroke_circle(center,radius)
409
+
410
+ ##
411
+ # :method: fill_circle
412
+ # Draws and fills a circle of radius +radius+ with the centre-point at +point+.
413
+ # :call-seq:
414
+ # fill_circle(center,radius)
415
+
416
+ ##
417
+ # :method: fill_and_stroke_circle
418
+ # Draws, strokes, and fills a circle of radius +radius+ with the centre-point at +point+.
419
+ # :call-seq:
420
+ # fill_and_stroke_circle(center,radius)
421
+
422
+ ##
423
+ # :method: stroke_ellipse
424
+ # Draws and strokes an ellipse of x radius +r1+ and y radius +r2+ with the centre-point at +point+.
425
+ # :call-seq:
426
+ # stroke_ellipse(point, r1, r2 = r1)
427
+
428
+ ##
429
+ # :method: fill_ellipse
430
+ # Draws and fills an ellipse of x radius +r1+ and y radius +r2+ with the centre-point at +point+.
431
+ # :call-seq:
432
+ # fill_ellipse(point, r1, r2 = r1)
433
+
434
+ ##
435
+ # :method: fill_and_stroke_ellipse
436
+ # Draws, strokes, and fills an ellipse of x radius +r1+ and y radius +r2+ with the centre-point at +point+.
437
+ # :call-seq:
438
+ # fill_and_stroke_ellipse(point, r1, r2 = r1)
439
+
440
+ ##
441
+ # :method: stroke_polygon
442
+ # Draws and strokes a polygon from the specified points.
443
+ # :call-seq:
444
+ # stroke_polygon(*points)
445
+
446
+ ##
447
+ # :method: fill_polygon
448
+ # Draws and fills a polygon from the specified points.
449
+ # :call-seq:
450
+ # fill_polygon(*points)
451
+
452
+ ##
453
+ # :method: fill_and_stroke_polygon
454
+ # Draws, strokes, and fills a polygon from the specified points.
455
+ # :call-seq:
456
+ # fill_and_stroke_polygon(*points)
457
+
458
+ ##
459
+ # :method: stroke_rounded_polygon
460
+ # Draws and strokes a rounded polygon from specified points, using +radius+ to define Bezier curves.
461
+ # :call-seq:
462
+ # stroke_rounded_polygon(radius, *points)
463
+
464
+ ##
465
+ # :method: fill_rounded_polygon
466
+ # Draws and fills a rounded polygon from specified points, using +radius+ to define Bezier curves.
467
+ # :call-seq:
468
+ # fill_rounded_polygon(radius, *points)
469
+
470
+ ##
471
+ # :method: fill_and_stroke_rounded_polygon
472
+ # Draws, strokes, and fills a rounded polygon from specified points, using +radius+ to define Bezier curves.
473
+ # :call-seq:
474
+ # fill_and_stroke_rounded_polygon(radius, *points)
475
+
476
+ ops = %w{fill stroke fill_and_stroke}
477
+ shapes = %w{line_to curve_to rectangle rounded_rectangle line horizontal_line horizontal_rule vertical_line
478
+ curve circle_at circle ellipse_at ellipse polygon rounded_polygon rounded_vertex}
479
+
480
+ ops.product(shapes).each do |operation,shape|
481
+ class_eval "def #{operation}_#{shape}(*args); #{shape}(*args); #{operation}; end"
357
482
  end
358
483
 
359
484
  private
@@ -95,7 +95,14 @@ module Prawn
95
95
  when String
96
96
  :RGB
97
97
  when Array
98
- :CMYK
98
+ case color.length
99
+ when 3
100
+ :RGB
101
+ when 4
102
+ :CMYK
103
+ else
104
+ raise ArgumentError, "Unknown type of color: #{color.inspect}"
105
+ end
99
106
  end
100
107
  end
101
108
 
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+
3
+ # patterns.rb : Implements axial & radial gradients
4
+ #
5
+ # Originally implemented by Wojciech Piekutowski. November, 2009
6
+ # Copyright September 2012, Alexander Mankuta. All Rights Reserved.
7
+ #
8
+ # This is free software. Please see the LICENSE and COPYING files for details.
9
+ #
10
+ module Prawn
11
+ module Graphics
12
+ module Patterns
13
+
14
+ # Sets the fill gradient from color1 to color2.
15
+ # old arguments: point, width, height, color1, color2, options = {}
16
+ # new arguments: from, to, color1, color1
17
+ # or from, r1, to, r2, color1, color2
18
+ def fill_gradient(*args)
19
+ if args[1].is_a?(Array) || args[2].is_a?(Array)
20
+ set_gradient(:fill, *args)
21
+ else
22
+ warn "[DEPRECATION] 'fill_gradient(point, width, height,...)' is deprecated in favor of 'fill_gradient(from, to,...)'. " +
23
+ "Old arguments will be removed in release 1.1"
24
+ set_gradient :fill, args[0], [args[0].first, args[0].last - args[2]], args[3], args[4]
25
+ end
26
+ end
27
+
28
+ # Sets the stroke gradient from color1 to color2.
29
+ # old arguments: point, width, height, color1, color2, options = {}
30
+ # new arguments: from, to, color1, color2
31
+ # or from, r1, to, r2, color1, color2
32
+ def stroke_gradient(*args)
33
+ if args[1].is_a?(Array) || args[2].is_a?(Array)
34
+ set_gradient(:stroke, *args)
35
+ else
36
+ warn "[DEPRECATION] 'stroke_gradient(point, width, height,...)' is deprecated in favor of 'stroke_gradient(from, to,...)'. " +
37
+ "Old arguments will be removed in release 1.1"
38
+ set_gradient :stroke, args[0], [args[0].first, args[0].last - args[2]], args[3], args[4]
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def set_gradient(type, *grad)
45
+ patterns = page.resources[:Pattern] ||= {}
46
+
47
+ registry_key = gradient_registry_key grad
48
+
49
+ if patterns["SP#{registry_key}"]
50
+ shading = patterns["SP#{registry_key}"]
51
+ else
52
+ unless shading = gradient_registry[registry_key]
53
+ shading = gradient(*grad)
54
+ gradient_registry[registry_key] = shading
55
+ end
56
+
57
+ patterns["SP#{registry_key}"] = shading
58
+ end
59
+
60
+ operator = case type
61
+ when :fill
62
+ 'scn'
63
+ when :stroke
64
+ 'SCN'
65
+ else
66
+ raise ArgumentError, "unknown type '#{type}'"
67
+ end
68
+
69
+ set_color_space type, :Pattern
70
+ add_content "/SP#{registry_key} #{operator}"
71
+ end
72
+
73
+ def gradient_registry_key(gradient)
74
+ if gradient[1].is_a?(Array) # axial
75
+ [
76
+ map_to_absolute(gradient[0]),
77
+ map_to_absolute(gradient[1]),
78
+ gradient[2], gradient[3]
79
+ ]
80
+ else # radial
81
+ [
82
+ map_to_absolute(gradient[0]),
83
+ gradient[1],
84
+ map_to_absolute(gradient[2]),
85
+ gradient[3],
86
+ gradient[4], gradient[5]
87
+ ]
88
+ end.hash
89
+ end
90
+
91
+ def gradient_registry
92
+ @gradient_registry ||= {}
93
+ end
94
+
95
+ def gradient(*args)
96
+ if args.length != 4 && args.length != 6
97
+ raise ArgumentError, "Unknown type of gradient: #{args.inspect}"
98
+ end
99
+
100
+ color1 = normalize_color(args[-2]).dup.freeze
101
+ color2 = normalize_color(args[-1]).dup.freeze
102
+
103
+ if color_type(color1) != color_type(color2)
104
+ raise ArgumentError, "Both colors must be of the same color space: #{color1.inspect} and #{color2.inspect}"
105
+ end
106
+
107
+ process_color color1
108
+ process_color color2
109
+
110
+ shader = ref!({
111
+ :FunctionType => 2,
112
+ :Domain => [0.0, 1.0],
113
+ :C0 => color1,
114
+ :C1 => color2,
115
+ :N => 1.0,
116
+ })
117
+
118
+ shading = ref!({
119
+ :ShadingType => args.length == 4 ? 2 : 3, # axial : radial shading
120
+ :ColorSpace => color_space(color1),
121
+ :Coords => args.length == 4 ?
122
+ [0, 0, args[1].first - args[0].first, args[1].last - args[0].last] :
123
+ [0, 0, args[1], args[2].first - args[0].first, args[2].last - args[0].last, args[3]],
124
+ :Function => shader,
125
+ :Extend => [true, true],
126
+ })
127
+
128
+ shading_pattern = ref!({
129
+ :PatternType => 2, # shading pattern
130
+ :Shading => shading,
131
+ :Matrix => [1, 0,
132
+ 0, 1] + map_to_absolute(args[0]),
133
+ })
134
+ end
135
+ end
136
+ end
137
+ end
@@ -14,8 +14,9 @@ module Prawn
14
14
  # Add the image at filename to the current page. Currently only
15
15
  # JPG and PNG files are supported.
16
16
  #
17
- # NOTE: Prawn is very slow at rendering PNGs with alpha channels. The
18
- # workaround for those who don't mind installing RMagick is to use:
17
+ # NOTE: Prawn is very slow at rendering PNGs with alpha channels, and this
18
+ # uses a lot of RAM. The workaround for those who don't mind installing
19
+ # RMagick is to use:
19
20
  #
20
21
  # http://github.com/amberbit/prawn-fast-png
21
22
  #
@@ -32,10 +33,10 @@ module Prawn
32
33
  # <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit inside [width,height]
33
34
  #
34
35
  # Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do
35
- # pigs = "#{Prawn::BASEDIR}/data/images/pigs.jpg"
36
+ # pigs = "#{Prawn::DATADIR}/images/pigs.jpg"
36
37
  # image pigs, :at => [50,450], :width => 450
37
38
  #
38
- # dice = "#{Prawn::BASEDIR}/data/images/dice.png"
39
+ # dice = "#{Prawn::DATADIR}/images/dice.png"
39
40
  # image dice, :at => [50, 450], :scale => 0.75
40
41
  # end
41
42
  #
@@ -76,6 +77,12 @@ module Prawn
76
77
  # the given image. Return a pair: [pdf_obj, info].
77
78
  #
78
79
  def build_image_object(file)
80
+ # Rewind if the object we're passed is an IO, so that multiple embeds of
81
+ # the same IO object will work
82
+ file.rewind if file.respond_to?(:rewind)
83
+ # read the file as binary so the size is calculated correctly
84
+ file.binmode if file.respond_to?(:binmode)
85
+
79
86
  if file.respond_to?(:read)
80
87
  image_content = file.read
81
88
  else
@@ -139,17 +146,6 @@ module Prawn
139
146
  def image_position(w,h,options)
140
147
  options[:position] ||= :left
141
148
 
142
- x = case options[:position]
143
- when :left
144
- bounds.absolute_left
145
- when :center
146
- bounds.absolute_left + (bounds.width - w) / 2.0
147
- when :right
148
- bounds.absolute_right - w
149
- when Numeric
150
- options[:position] + bounds.absolute_left
151
- end
152
-
153
149
  y = case options[:vposition]
154
150
  when :top
155
151
  bounds.absolute_top
@@ -162,16 +158,26 @@ module Prawn
162
158
  else
163
159
  determine_y_with_page_flow(h)
164
160
  end
161
+
162
+ x = case options[:position]
163
+ when :left
164
+ bounds.left_side
165
+ when :center
166
+ bounds.left_side + (bounds.width - w) / 2.0
167
+ when :right
168
+ bounds.right_side - w
169
+ when Numeric
170
+ options[:position] + bounds.left_side
171
+ end
172
+
165
173
  return [x,y]
166
174
  end
167
175
 
168
176
  def determine_y_with_page_flow(h)
169
177
  if overruns_page?(h)
170
- start_new_page
171
- bounds.absolute_top
172
- else
173
- self.y
178
+ bounds.move_past_bottom
174
179
  end
180
+ self.y
175
181
  end
176
182
 
177
183
  def overruns_page?(h)