prawn 1.1.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +1 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +9 -40
  7. data/lib/prawn/document/bounding_box.rb +54 -40
  8. data/lib/prawn/document/column_box.rb +8 -10
  9. data/lib/prawn/document/internals.rb +39 -146
  10. data/lib/prawn/document/span.rb +23 -17
  11. data/lib/prawn/document.rb +217 -182
  12. data/lib/prawn/encoding.rb +69 -101
  13. data/lib/prawn/errors.rb +47 -43
  14. data/lib/prawn/font.rb +124 -104
  15. data/lib/prawn/font_metric_cache.rb +23 -21
  16. data/lib/prawn/fonts/afm.rb +292 -0
  17. data/lib/prawn/{font → fonts}/dfont.rb +5 -12
  18. data/lib/prawn/fonts/otf.rb +11 -0
  19. data/lib/prawn/fonts/ttc.rb +36 -0
  20. data/lib/prawn/{font → fonts}/ttf.rb +140 -88
  21. data/lib/prawn/graphics/blend_mode.rb +65 -0
  22. data/lib/prawn/graphics/cap_style.rb +5 -5
  23. data/lib/prawn/graphics/color.rb +46 -44
  24. data/lib/prawn/graphics/dash.rb +27 -11
  25. data/lib/prawn/graphics/join_style.rb +11 -6
  26. data/lib/prawn/graphics/patterns.rb +220 -78
  27. data/lib/prawn/graphics/transformation.rb +20 -12
  28. data/lib/prawn/graphics/transparency.rb +20 -18
  29. data/lib/prawn/graphics.rb +153 -115
  30. data/lib/prawn/grid.rb +93 -50
  31. data/lib/prawn/image_handler.rb +4 -4
  32. data/lib/prawn/images/image.rb +3 -2
  33. data/lib/prawn/images/jpg.rb +31 -24
  34. data/lib/prawn/images/png.rb +101 -68
  35. data/lib/prawn/images.rb +64 -56
  36. data/lib/prawn/measurement_extensions.rb +10 -9
  37. data/lib/prawn/measurements.rb +20 -23
  38. data/lib/prawn/outline.rb +96 -75
  39. data/lib/prawn/repeater.rb +16 -16
  40. data/lib/prawn/security/arcfour.rb +2 -2
  41. data/lib/prawn/security.rb +100 -85
  42. data/lib/prawn/soft_mask.rb +37 -38
  43. data/lib/prawn/stamp.rb +28 -13
  44. data/lib/prawn/text/box.rb +24 -29
  45. data/lib/prawn/text/formatted/arranger.rb +108 -63
  46. data/lib/prawn/text/formatted/box.rb +187 -124
  47. data/lib/prawn/text/formatted/fragment.rb +24 -20
  48. data/lib/prawn/text/formatted/line_wrap.rb +133 -73
  49. data/lib/prawn/text/formatted/parser.rb +147 -127
  50. data/lib/prawn/text/formatted/wrap.rb +48 -35
  51. data/lib/prawn/text/formatted.rb +5 -5
  52. data/lib/prawn/text.rb +103 -68
  53. data/lib/prawn/transformation_stack.rb +44 -0
  54. data/lib/prawn/utilities.rb +10 -22
  55. data/lib/prawn/version.rb +5 -0
  56. data/lib/prawn/view.rb +101 -0
  57. data/lib/prawn.rb +39 -54
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +34 -25
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +8 -9
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +48 -0
  66. data/manual/bounding_box/bounding_box.rb +30 -28
  67. data/manual/bounding_box/bounds.rb +12 -13
  68. data/manual/bounding_box/canvas.rb +7 -8
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +25 -18
  72. data/manual/bounding_box/russian_boxes.rb +18 -18
  73. data/manual/bounding_box/stretchy.rb +12 -14
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -32
  76. data/manual/document_and_page_options/background.rb +15 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +24 -22
  78. data/manual/document_and_page_options/metadata.rb +20 -18
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -13
  81. data/manual/document_and_page_options/print_scaling.rb +18 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +5 -6
  88. data/manual/graphics/fill_rules.rb +12 -11
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +46 -40
  91. data/manual/graphics/helper.rb +19 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +8 -9
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -9
  97. data/manual/graphics/scale.rb +14 -13
  98. data/manual/graphics/soft_masks.rb +4 -6
  99. data/manual/graphics/stroke_cap.rb +7 -8
  100. data/manual/graphics/stroke_dash.rb +15 -16
  101. data/manual/graphics/stroke_join.rb +6 -7
  102. data/manual/graphics/translate.rb +10 -10
  103. data/manual/graphics/transparency.rb +7 -9
  104. data/manual/how_to_read_this_manual.rb +8 -9
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +10 -11
  108. data/manual/images/images.rb +28 -27
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +16 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +10 -11
  114. data/manual/layout/content.rb +9 -10
  115. data/manual/layout/layout.rb +17 -18
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +22 -21
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +27 -23
  124. data/manual/repeatable_content/repeater.rb +15 -16
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +8 -11
  127. data/manual/security/permissions.rb +20 -15
  128. data/manual/security/security.rb +18 -18
  129. data/manual/table.rb +16 -0
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -12
  132. data/manual/text/column_box.rb +9 -11
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +10 -8
  137. data/manual/text/formatted_callbacks.rb +33 -23
  138. data/manual/text/formatted_text.rb +36 -25
  139. data/manual/text/free_flowing_text.rb +22 -23
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +15 -10
  145. data/manual/text/positioned_text.rb +16 -17
  146. data/manual/text/registering_families.rb +27 -24
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +30 -19
  149. data/manual/text/rotation.rb +33 -24
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +56 -54
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +24 -17
  155. data/manual/text/utf8.rb +12 -13
  156. data/manual/text/win_ansi_charset.rb +28 -25
  157. data/prawn.gemspec +45 -50
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +44 -0
  167. data/spec/prawn/document_spec.rb +805 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +544 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +872 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +229 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +512 -0
  180. data/spec/prawn/repeater_spec.rb +166 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +173 -0
  183. data/spec/prawn/text/box_spec.rb +1110 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +150 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -25
  198. data.tar.gz.sig +0 -0
  199. metadata +113 -276
  200. metadata.gz.sig +0 -0
  201. data/data/encodings/win_ansi.txt +0 -29
  202. data/data/images/16bit.alpha +0 -0
  203. data/data/images/16bit.color +0 -0
  204. data/data/images/16bit.png +0 -0
  205. data/data/images/arrow.png +0 -0
  206. data/data/images/arrow2.png +0 -0
  207. data/data/images/dice.alpha +0 -0
  208. data/data/images/dice.color +0 -0
  209. data/data/images/dice.png +0 -0
  210. data/data/images/dice_interlaced.png +0 -0
  211. data/data/images/fractal.jpg +0 -0
  212. data/data/images/indexed_color.dat +0 -0
  213. data/data/images/indexed_color.png +0 -0
  214. data/data/images/letterhead.jpg +0 -0
  215. data/data/images/license.md +0 -8
  216. data/data/images/page_white_text.alpha +0 -0
  217. data/data/images/page_white_text.color +0 -0
  218. data/data/images/page_white_text.png +0 -0
  219. data/data/images/pigs.jpg +0 -0
  220. data/data/images/prawn.png +0 -0
  221. data/data/images/ruport.png +0 -0
  222. data/data/images/ruport_data.dat +0 -0
  223. data/data/images/ruport_transparent.png +0 -0
  224. data/data/images/ruport_type0.png +0 -0
  225. data/data/images/stef.jpg +0 -0
  226. data/data/images/tru256.bmp +0 -0
  227. data/data/images/web-links.dat +0 -1
  228. data/data/images/web-links.png +0 -0
  229. data/data/pdfs/complex_template.pdf +0 -0
  230. data/data/pdfs/contains_ttf_font.pdf +0 -0
  231. data/data/pdfs/encrypted.pdf +0 -0
  232. data/data/pdfs/form.pdf +1 -819
  233. data/data/pdfs/hexagon.pdf +0 -61
  234. data/data/pdfs/indirect_reference.pdf +0 -86
  235. data/data/pdfs/multipage_template.pdf +0 -127
  236. data/data/pdfs/nested_pages.pdf +0 -118
  237. data/data/pdfs/page_without_mediabox.pdf +0 -193
  238. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  239. data/data/pdfs/two_hexagons.pdf +0 -90
  240. data/data/pdfs/version_1_6.pdf +0 -61
  241. data/data/shift_jis_text.txt +0 -1
  242. data/lib/prawn/document/graphics_state.rb +0 -73
  243. data/lib/prawn/font/afm.rb +0 -247
  244. data/lib/prawn/table/cell/image.rb +0 -69
  245. data/lib/prawn/table/cell/in_table.rb +0 -33
  246. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  247. data/lib/prawn/table/cell/subtable.rb +0 -66
  248. data/lib/prawn/table/cell/text.rb +0 -154
  249. data/lib/prawn/table/cell.rb +0 -772
  250. data/lib/prawn/table/cells.rb +0 -255
  251. data/lib/prawn/table/column_width_calculator.rb +0 -182
  252. data/lib/prawn/table.rb +0 -644
  253. data/manual/table/basic_block.rb +0 -53
  254. data/manual/table/before_rendering_page.rb +0 -26
  255. data/manual/table/cell_border_lines.rb +0 -24
  256. data/manual/table/cell_borders_and_bg.rb +0 -31
  257. data/manual/table/cell_dimensions.rb +0 -30
  258. data/manual/table/cell_text.rb +0 -38
  259. data/manual/table/column_widths.rb +0 -30
  260. data/manual/table/content_and_subtables.rb +0 -39
  261. data/manual/table/creation.rb +0 -27
  262. data/manual/table/filtering.rb +0 -36
  263. data/manual/table/flow_and_header.rb +0 -17
  264. data/manual/table/image_cells.rb +0 -33
  265. data/manual/table/position.rb +0 -29
  266. data/manual/table/row_colors.rb +0 -20
  267. data/manual/table/span.rb +0 -30
  268. data/manual/table/style.rb +0 -22
  269. data/manual/table/table.rb +0 -52
  270. data/manual/table/width.rb +0 -27
  271. data/spec/acceptance/png.rb +0 -25
  272. data/spec/annotations_spec.rb +0 -74
  273. data/spec/bounding_box_spec.rb +0 -510
  274. data/spec/cell_spec.rb +0 -629
  275. data/spec/column_box_spec.rb +0 -65
  276. data/spec/destinations_spec.rb +0 -15
  277. data/spec/document_spec.rb +0 -730
  278. data/spec/extensions/mocha.rb +0 -46
  279. data/spec/font_metric_cache_spec.rb +0 -52
  280. data/spec/font_spec.rb +0 -449
  281. data/spec/formatted_text_arranger_spec.rb +0 -421
  282. data/spec/formatted_text_box_spec.rb +0 -639
  283. data/spec/formatted_text_fragment_spec.rb +0 -298
  284. data/spec/graphics_spec.rb +0 -669
  285. data/spec/grid_spec.rb +0 -96
  286. data/spec/image_handler_spec.rb +0 -54
  287. data/spec/images_spec.rb +0 -153
  288. data/spec/inline_formatted_text_parser_spec.rb +0 -564
  289. data/spec/jpg_spec.rb +0 -25
  290. data/spec/line_wrap_spec.rb +0 -344
  291. data/spec/measurement_units_spec.rb +0 -25
  292. data/spec/outline_spec.rb +0 -430
  293. data/spec/png_spec.rb +0 -237
  294. data/spec/reference_spec.rb +0 -25
  295. data/spec/repeater_spec.rb +0 -160
  296. data/spec/security_spec.rb +0 -158
  297. data/spec/soft_mask_spec.rb +0 -79
  298. data/spec/span_spec.rb +0 -44
  299. data/spec/stamp_spec.rb +0 -160
  300. data/spec/stroke_styles_spec.rb +0 -211
  301. data/spec/table/span_dummy_spec.rb +0 -17
  302. data/spec/table_spec.rb +0 -1527
  303. data/spec/text_at_spec.rb +0 -115
  304. data/spec/text_box_spec.rb +0 -1034
  305. data/spec/text_rendering_mode_spec.rb +0 -45
  306. data/spec/text_spacing_spec.rb +0 -93
  307. data/spec/text_spec.rb +0 -437
  308. data/spec/text_with_inline_formatting_spec.rb +0 -35
  309. data/spec/transparency_spec.rb +0 -91
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # prawn/font/ttf.rb : Implements AFM font support for Prawn
4
4
  #
@@ -11,45 +11,68 @@ require 'ttfunk'
11
11
  require 'ttfunk/subset_collection'
12
12
 
13
13
  module Prawn
14
- class Font
15
-
14
+ module Fonts
16
15
  # @private
17
16
  class TTF < Font
17
+ class Error < StandardError
18
+ DEFAULT_MESSAGE = 'TTF font error'
19
+ MESSAGE_WITH_FONT = 'TTF font error in font %<font>s'
20
+
21
+ def initialize(message = DEFAULT_MESSAGE, font: nil)
22
+ if font && message == DEFAULT_MESSAGE
23
+ super format(MESSAGE_WITH_FONT, font: font)
24
+ else
25
+ super message
26
+ end
27
+ end
28
+ end
29
+
30
+ class NoUnicodeCMap < Error
31
+ DEFAULT_MESSAGE = 'No unicode cmap found in font'
32
+ MESSAGE_WITH_FONT = 'No unicode cmap found in font %<font>s'
33
+ end
34
+
35
+ class NoPostscriptName < Error
36
+ DEFAULT_MESSAGE = 'Can not detect a postscript name'
37
+ MESSAGE_WITH_FONT = 'Can not detect a postscript name in font %<font>s'
38
+ end
39
+
18
40
  attr_reader :ttf, :subsets
19
41
 
20
42
  def unicode?
21
43
  true
22
44
  end
23
45
 
24
- def initialize(document, name, options={})
46
+ def initialize(document, name, options = {})
25
47
  super
26
48
 
27
- @ttf = read_ttf_file
28
- @subsets = TTFunk::SubsetCollection.new(@ttf)
49
+ @ttf = read_ttf_file
50
+ @subsets = TTFunk::SubsetCollection.new(@ttf)
51
+ @italic_angle = nil
29
52
 
30
- @attributes = {}
31
- @bounding_boxes = {}
32
- @char_widths = {}
53
+ @attributes = {}
54
+ @bounding_boxes = {}
55
+ @char_widths = {}
33
56
  @has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
34
57
 
35
- @ascender = Integer(@ttf.ascent * scale_factor)
36
- @descender = Integer(@ttf.descent * scale_factor)
37
- @line_gap = Integer(@ttf.line_gap * scale_factor)
58
+ @ascender = Integer(@ttf.ascent * scale_factor)
59
+ @descender = Integer(@ttf.descent * scale_factor)
60
+ @line_gap = Integer(@ttf.line_gap * scale_factor)
38
61
  end
39
62
 
40
63
  # NOTE: +string+ must be UTF8-encoded.
41
- def compute_width_of(string, options={}) #:nodoc:
64
+ def compute_width_of(string, options = {}) #:nodoc:
42
65
  scale = (options[:size] || size) / 1000.0
43
66
  if options[:kerning]
44
- kern(string).inject(0) do |s,r|
67
+ kern(string).reduce(0) do |s, r|
45
68
  if r.is_a?(Numeric)
46
69
  s - r
47
70
  else
48
- r.inject(s) { |s2, u| s2 + character_width_by_code(u) }
71
+ r.reduce(s) { |a, e| a + character_width_by_code(e) }
49
72
  end
50
73
  end * scale
51
74
  else
52
- string.codepoints.inject(0) do |s,r|
75
+ string.codepoints.reduce(0) do |s, r|
53
76
  s + character_width_by_code(r)
54
77
  end * scale
55
78
  end
@@ -62,9 +85,12 @@ module Prawn
62
85
  end
63
86
 
64
87
  # Returns true if the font has kerning data, false otherwise
88
+ #
89
+ # rubocop: disable Naming/PredicateName
65
90
  def has_kerning_data?
66
91
  @has_kerning_data
67
92
  end
93
+ # rubocop: enable Naming/PredicateName
68
94
 
69
95
  # Perform any changes to the string that need to happen
70
96
  # before it is rendered to the canvas. Returns an array of
@@ -74,14 +100,16 @@ module Prawn
74
100
  #
75
101
  # The +text+ parameter must be UTF8-encoded.
76
102
  #
77
- def encode_text(text,options={})
103
+ def encode_text(text, options = {})
78
104
  text = text.chomp
79
105
 
80
106
  if options[:kerning]
81
107
  last_subset = nil
82
- kern(text).inject([]) do |result, element|
108
+ kern(text).reduce([]) do |result, element|
83
109
  if element.is_a?(Numeric)
84
- result.last[1] = [result.last[1]] unless result.last[1].is_a?(Array)
110
+ unless result.last[1].is_a?(Array)
111
+ result.last[1] = [result.last[1]]
112
+ end
85
113
  result.last[1] << element
86
114
  result
87
115
  else
@@ -101,7 +129,7 @@ module Prawn
101
129
  end
102
130
  end
103
131
  else
104
- @subsets.encode(text.unpack("U*"))
132
+ @subsets.encode(text.unpack('U*'))
105
133
  end
106
134
  end
107
135
 
@@ -110,26 +138,32 @@ module Prawn
110
138
  end
111
139
 
112
140
  # not sure how to compute this for true-type fonts...
113
- def stemV
141
+ def stem_v
114
142
  0
115
143
  end
116
144
 
117
145
  def italic_angle
118
- @italic_angle ||= if @ttf.postscript.exists?
146
+ return @italic_angle if @italic_angle
147
+
148
+ if @ttf.postscript.exists?
119
149
  raw = @ttf.postscript.italic_angle
120
- hi, low = raw >> 16, raw & 0xFF
150
+ hi = raw >> 16
151
+ low = raw & 0xFF
121
152
  hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
122
- "#{hi}.#{low}".to_f
153
+ @italic_angle = "#{hi}.#{low}".to_f
123
154
  else
124
- 0
155
+ @italic_angle = 0
125
156
  end
157
+
158
+ @italic_angle
126
159
  end
127
160
 
128
161
  def cap_height
129
- @cap_height ||= begin
130
- height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
131
- height == 0 ? @ascender : height
132
- end
162
+ @cap_height ||=
163
+ begin
164
+ height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
165
+ height.zero? ? @ascender : height
166
+ end
133
167
  end
134
168
 
135
169
  def x_height
@@ -143,7 +177,7 @@ module Prawn
143
177
  end
144
178
 
145
179
  def serif?
146
- @serif ||= [1,2,3,4,5,7].include?(family_class)
180
+ @serif ||= [1, 2, 3, 4, 5, 7].include?(family_class)
147
181
  end
148
182
 
149
183
  def script?
@@ -151,31 +185,35 @@ module Prawn
151
185
  end
152
186
 
153
187
  def pdf_flags
154
- @flags ||= begin
155
- flags = 0
156
- flags |= 0x0001 if @ttf.postscript.fixed_pitch?
157
- flags |= 0x0002 if serif?
158
- flags |= 0x0008 if script?
159
- flags |= 0x0040 if italic_angle != 0
160
- flags |= 0x0004 # assume the font contains at least some non-latin characters
161
- end
188
+ @pdf_flags ||=
189
+ begin
190
+ flags = 0
191
+ flags |= 0x0001 if @ttf.postscript.fixed_pitch?
192
+ flags |= 0x0002 if serif?
193
+ flags |= 0x0008 if script?
194
+ flags |= 0x0040 if italic_angle != 0
195
+ # Assume the font contains at least some non-latin characters
196
+ flags | 0x0004
197
+ end
162
198
  end
163
199
 
164
200
  def normalize_encoding(text)
165
- begin
166
- text.encode(::Encoding::UTF_8)
167
- rescue => e
168
- puts e
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
201
+ text.encode(::Encoding::UTF_8)
202
+ rescue StandardError => e
203
+ puts e
204
+ raise Prawn::Errors::IncompatibleStringEncoding,
205
+ "Encoding #{text.encoding} can not be transparently converted to UTF-8. " \
206
+ 'Please ensure the encoding of the string you are attempting ' \
207
+ 'to use is set correctly'
208
+ end
209
+
210
+ def to_utf8(text)
211
+ text.encode('UTF-8')
174
212
  end
175
213
 
176
214
  def glyph_present?(char)
177
215
  code = char.codepoints.first
178
- cmap[code] > 0
216
+ cmap[code].positive?
179
217
  end
180
218
 
181
219
  # Returns the number of characters in +str+ (a UTF-8-encoded string).
@@ -187,7 +225,7 @@ module Prawn
187
225
  private
188
226
 
189
227
  def cmap
190
- @cmap ||= @ttf.cmap.unicode.first or raise("no unicode cmap for font")
228
+ (@cmap ||= @ttf.cmap.unicode.first) || raise(NoUnicodeCMap.new(font: name))
191
229
  end
192
230
 
193
231
  # +string+ must be UTF8-encoded.
@@ -213,12 +251,12 @@ module Prawn
213
251
  end
214
252
 
215
253
  def kern_pairs_table
216
- @kerning_data ||= has_kerning_data? ? @ttf.kerning.tables.first.pairs : {}
217
- end
218
-
219
- def cid_to_gid_map
220
- max = cmap.code_map.keys.max
221
- (0..max).map { |cid| cmap[cid] }.pack("n*")
254
+ @kern_pairs_table ||=
255
+ if has_kerning_data?
256
+ @ttf.kerning.tables.first.pairs
257
+ else
258
+ {}
259
+ end
222
260
  end
223
261
 
224
262
  def hmtx
@@ -236,16 +274,16 @@ module Prawn
236
274
  end
237
275
 
238
276
  def scale_factor
239
- @scale ||= 1000.0 / @ttf.header.units_per_em
277
+ @scale_factor ||= 1000.0 / @ttf.header.units_per_em
240
278
  end
241
279
 
242
280
  def register(subset)
243
- temp_name = @ttf.name.postscript_name.gsub("\0","").to_sym
244
- ref = @document.ref!(:Type => :Font, :BaseFont => temp_name)
281
+ temp_name = @ttf.name.postscript_name.delete("\0").to_sym
282
+ ref = @document.ref!(Type: :Font, BaseFont: temp_name)
245
283
 
246
284
  # Embed the font metrics in the document after everything has been
247
285
  # drawn, just before the document is emitted.
248
- @document.before_render { |doc| embed(ref, subset) }
286
+ @document.renderer.before_render { |_doc| embed(ref, subset) }
249
287
 
250
288
  ref
251
289
  end
@@ -260,29 +298,32 @@ module Prawn
260
298
 
261
299
  # empirically, it looks like Adobe Reader will not display fonts
262
300
  # if their font name is more than 33 bytes long. Strange. But true.
263
- basename = font.name.postscript_name[0, 33].gsub("\0","")
301
+ basename = font.name.postscript_name[0, 33].delete("\0")
264
302
 
265
- raise "Can't detect a postscript name for #{file}" if basename.nil?
303
+ raise NoPostscriptName.new(font: font) if basename.nil?
266
304
 
267
- fontfile = @document.ref!(:Length1 => font_content.size)
305
+ fontfile = @document.ref!(Length1: font_content.size)
268
306
  fontfile.stream << font_content
269
307
  fontfile.stream.compress!
270
308
 
271
- descriptor = @document.ref!(:Type => :FontDescriptor,
272
- :FontName => basename.to_sym,
273
- :FontFile2 => fontfile,
274
- :FontBBox => bbox,
275
- :Flags => pdf_flags,
276
- :StemV => stemV,
277
- :ItalicAngle => italic_angle,
278
- :Ascent => @ascender,
279
- :Descent => @descender,
280
- :CapHeight => cap_height,
281
- :XHeight => x_height)
309
+ descriptor = @document.ref!(
310
+ Type: :FontDescriptor,
311
+ FontName: basename.to_sym,
312
+ FontFile2: fontfile,
313
+ FontBBox: bbox,
314
+ Flags: pdf_flags,
315
+ StemV: stem_v,
316
+ ItalicAngle: italic_angle,
317
+ Ascent: @ascender,
318
+ Descent: @descender,
319
+ CapHeight: cap_height,
320
+ XHeight: x_height
321
+ )
282
322
 
283
323
  hmtx = font.horizontal_metrics
284
- widths = font.cmap.tables.first.code_map.map { |gid|
285
- Integer(hmtx.widths[gid] * scale_factor) }[32..-1]
324
+ widths = font.cmap.tables.first.code_map.map do |gid|
325
+ Integer(hmtx.widths[gid] * scale_factor)
326
+ end[32..-1]
286
327
 
287
328
  # It would be nice to have Encoding set for the macroman subsets,
288
329
  # and only do a ToUnicode cmap for non-encoded unicode subsets.
@@ -297,15 +338,24 @@ module Prawn
297
338
  map = @subsets[subset].to_unicode_map
298
339
 
299
340
  ranges = [[]]
300
- map.keys.sort.inject("") do |s, code|
341
+ map.keys.sort.reduce('') do |_s, code|
301
342
  ranges << [] if ranges.last.length >= 100
302
343
  unicode = map[code]
303
- ranges.last << "<%02x><%04x>" % [code, unicode]
344
+ ranges.last << format(
345
+ '<%<code>02x><%<unicode>04x>',
346
+ code: code,
347
+ unicode: unicode
348
+ )
304
349
  end
305
350
 
306
- range_blocks = ranges.inject("") do |s, list|
307
- s << "%d beginbfchar\n%s\nendbfchar\n" % [list.length, list.join("\n")]
308
- end
351
+ range_blocks =
352
+ ranges.reduce(+'') do |s, list|
353
+ s << format(
354
+ "%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
355
+ lenght: list.length,
356
+ list: list.join("\n")
357
+ )
358
+ end
309
359
 
310
360
  to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
311
361
 
@@ -313,16 +363,18 @@ module Prawn
313
363
  cmap << to_unicode_cmap
314
364
  cmap.stream.compress!
315
365
 
316
- reference.data.update(:Subtype => :TrueType,
317
- :BaseFont => basename.to_sym,
318
- :FontDescriptor => descriptor,
319
- :FirstChar => 32,
320
- :LastChar => 255,
321
- :Widths => @document.ref!(widths),
322
- :ToUnicode => cmap)
366
+ reference.data.update(
367
+ Subtype: :TrueType,
368
+ BaseFont: basename.to_sym,
369
+ FontDescriptor: descriptor,
370
+ FirstChar: 32,
371
+ LastChar: 255,
372
+ Widths: @document.ref!(widths),
373
+ ToUnicode: cmap
374
+ )
323
375
  end
324
376
 
325
- UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, "")
377
+ UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, '')
326
378
  /CIDInit /ProcSet findresource begin
327
379
  12 dict begin
328
380
  begincmap
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # blend_mode.rb : Implements blend modes
4
+ #
5
+ # Contributed by John Ford. October, 2015
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ #
9
+
10
+ module Prawn
11
+ module Graphics
12
+ # The Prawn::BlendMode module is used to change the way
13
+ # two layers are blended together.
14
+ #
15
+ # Passing an array of blend modes is allowed. PDF viewers should
16
+ # blend layers based on the first recognized blend mode.
17
+ #
18
+ # Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply,
19
+ # :Screen, :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight,
20
+ # :SoftLight, :Difference, :Exclusion, :Hue, :Saturation, :Color, and
21
+ # :Luminosity.
22
+ #
23
+ # Example:
24
+ # pdf.fill_color('0000ff')
25
+ # pdf.fill_rectangle([x, y+25], 50, 50)
26
+ # pdf.blend_mode(:Multiply) do
27
+ # pdf.fill_color('ff0000')
28
+ # pdf.fill_circle([x, y], 25)
29
+ # end
30
+ #
31
+ module BlendMode
32
+ # @group Stable API
33
+
34
+ def blend_mode(blend_mode = :Normal)
35
+ renderer.min_version(1.4)
36
+
37
+ save_graphics_state if block_given?
38
+ renderer.add_content "/#{blend_mode_dictionary_name(blend_mode)} gs"
39
+ if block_given?
40
+ yield
41
+ restore_graphics_state
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def blend_mode_dictionary_registry
48
+ @blend_mode_dictionary_registry ||= {}
49
+ end
50
+
51
+ def blend_mode_dictionary_name(blend_mode)
52
+ key = Array(blend_mode).join('')
53
+ dictionary_name = "BM#{key}"
54
+
55
+ dictionary = blend_mode_dictionary_registry[dictionary_name] ||= ref!(
56
+ Type: :ExtGState,
57
+ BM: blend_mode
58
+ )
59
+
60
+ page.ext_gstates[dictionary_name] = dictionary
61
+ dictionary_name
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # cap_style.rb : Implements stroke cap styling
4
4
  #
@@ -11,7 +11,7 @@ module Prawn
11
11
  module CapStyle
12
12
  # @group Stable API
13
13
 
14
- CAP_STYLES = { :butt => 0, :round => 1, :projecting_square => 2 }
14
+ CAP_STYLES = { butt: 0, round: 1, projecting_square: 2 }.freeze
15
15
 
16
16
  # Sets the cap style for stroked lines and curves
17
17
  #
@@ -19,7 +19,7 @@ module Prawn
19
19
  #
20
20
  # NOTE: If this method is never called, :butt will be used by default.
21
21
  #
22
- def cap_style(style=nil)
22
+ def cap_style(style = nil)
23
23
  return current_cap_style || :butt if style.nil?
24
24
 
25
25
  self.current_cap_style = style
@@ -27,7 +27,7 @@ module Prawn
27
27
  write_stroke_cap_style
28
28
  end
29
29
 
30
- alias_method :cap_style=, :cap_style
30
+ alias cap_style= cap_style
31
31
 
32
32
  private
33
33
 
@@ -40,7 +40,7 @@ module Prawn
40
40
  end
41
41
 
42
42
  def write_stroke_cap_style
43
- add_content "#{CAP_STYLES[current_cap_style]} J"
43
+ renderer.add_content "#{CAP_STYLES[current_cap_style]} J"
44
44
  end
45
45
  end
46
46
  end
@@ -1,4 +1,4 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  # color.rb : Implements color handling
4
4
  #
@@ -27,11 +27,12 @@ module Prawn
27
27
  #
28
28
  def fill_color(*color)
29
29
  return current_fill_color if color.empty?
30
+
30
31
  self.current_fill_color = process_color(*color)
31
32
  set_fill_color
32
33
  end
33
34
 
34
- alias_method :fill_color=, :fill_color
35
+ alias fill_color= fill_color
35
36
 
36
37
  # Sets or returns the line stroking color.
37
38
  #
@@ -49,12 +50,13 @@ module Prawn
49
50
  #
50
51
  def stroke_color(*color)
51
52
  return current_stroke_color if color.empty?
53
+
52
54
  color = process_color(*color)
53
55
  self.current_stroke_color = color
54
56
  set_stroke_color(color)
55
57
  end
56
58
 
57
- alias_method :stroke_color=, :stroke_color
59
+ alias stroke_color= stroke_color
58
60
 
59
61
  module_function
60
62
 
@@ -65,7 +67,7 @@ module Prawn
65
67
  # => "ff7808"
66
68
  #
67
69
  def rgb2hex(rgb)
68
- rgb.map { |e| "%02x" % e }.join
70
+ rgb.map { |e| format '%<value>02x', value: e }.join
69
71
  end
70
72
 
71
73
  # Converts hex string into RGB value array:
@@ -74,14 +76,16 @@ module Prawn
74
76
  # => [255, 120, 8]
75
77
  #
76
78
  def hex2rgb(hex)
77
- r,g,b = hex[0..1], hex[2..3], hex[4..5]
78
- [r,g,b].map { |e| e.to_i(16) }
79
+ r = hex[0..1]
80
+ g = hex[2..3]
81
+ b = hex[4..5]
82
+ [r, g, b].map { |e| e.to_i(16) }
79
83
  end
80
84
 
81
85
  private
82
86
 
83
87
  def process_color(*color)
84
- case(color.size)
88
+ case color.size
85
89
  when 1
86
90
  color[0]
87
91
  when 4
@@ -94,7 +98,11 @@ module Prawn
94
98
  def color_type(color)
95
99
  case color
96
100
  when String
97
- :RGB
101
+ if /\A\h{6}\z/.match?(color)
102
+ :RGB
103
+ else
104
+ raise ArgumentError, "Unknown type of color: #{color.inspect}"
105
+ end
98
106
  when Array
99
107
  case color.length
100
108
  when 3
@@ -110,16 +118,16 @@ module Prawn
110
118
  def normalize_color(color)
111
119
  case color_type(color)
112
120
  when :RGB
113
- r,g,b = hex2rgb(color)
121
+ r, g, b = hex2rgb(color)
114
122
  [r / 255.0, g / 255.0, b / 255.0]
115
123
  when :CMYK
116
- c,m,y,k = *color
124
+ c, m, y, k = *color
117
125
  [c / 100.0, m / 100.0, y / 100.0, k / 100.0]
118
126
  end
119
127
  end
120
128
 
121
129
  def color_to_s(color)
122
- normalize_color(color).map { |c| '%.3f' % c }.join(' ')
130
+ PDF::Core.real_params normalize_color(color)
123
131
  end
124
132
 
125
133
  def color_space(color)
@@ -131,42 +139,48 @@ module Prawn
131
139
  end
132
140
  end
133
141
 
134
- COLOR_SPACES = [:DeviceRGB, :DeviceCMYK, :Pattern]
142
+ COLOR_SPACES = %i[DeviceRGB DeviceCMYK Pattern].freeze
135
143
 
136
144
  def set_color_space(type, color_space)
137
145
  # don't set the same color space again
138
- return if current_color_space(type) == color_space && !state.page.in_stamp_stream?
146
+ if current_color_space(type) == color_space &&
147
+ !state.page.in_stamp_stream?
148
+ return
149
+ end
150
+
139
151
  set_current_color_space(color_space, type)
140
152
 
141
153
  unless COLOR_SPACES.include?(color_space)
142
154
  raise ArgumentError, "unknown color space: '#{color_space}'"
143
155
  end
144
156
 
145
- operator = case type
146
- when :fill
147
- 'cs'
148
- when :stroke
149
- 'CS'
150
- else
151
- raise ArgumentError, "unknown type '#{type}'"
152
- end
157
+ operator =
158
+ case type
159
+ when :fill
160
+ 'cs'
161
+ when :stroke
162
+ 'CS'
163
+ else
164
+ raise ArgumentError, "unknown type '#{type}'"
165
+ end
153
166
 
154
- add_content "/#{color_space} #{operator}"
167
+ renderer.add_content "/#{color_space} #{operator}"
155
168
  end
156
169
 
157
170
  def set_color(type, color, options = {})
158
- operator = case type
159
- when :fill
160
- 'scn'
161
- when :stroke
162
- 'SCN'
163
- else
164
- raise ArgumentError, "unknown type '#{type}'"
165
- end
171
+ operator =
172
+ case type
173
+ when :fill
174
+ 'scn'
175
+ when :stroke
176
+ 'SCN'
177
+ else
178
+ raise ArgumentError, "unknown type '#{type}'"
179
+ end
166
180
 
167
181
  if options[:pattern]
168
182
  set_color_space type, :Pattern
169
- add_content "/#{color} #{operator}"
183
+ renderer.add_content "/#{color} #{operator}"
170
184
  else
171
185
  set_color_space type, color_space(color)
172
186
  color = color_to_s(color)
@@ -187,8 +201,6 @@ module Prawn
187
201
  set_stroke_color
188
202
  end
189
203
 
190
- private
191
-
192
204
  def current_color_space(type)
193
205
  graphic_state.color_space[type]
194
206
  end
@@ -214,19 +226,9 @@ module Prawn
214
226
  graphic_state.stroke_color = color
215
227
  end
216
228
 
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
229
  def write_color(color, operator)
226
- add_content "#{color} #{operator}"
230
+ renderer.add_content "#{color} #{operator}"
227
231
  end
228
-
229
232
  end
230
233
  end
231
234
  end
232
-