prawn 0.13.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 (348) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +10 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -16
  6. data/Rakefile +17 -39
  7. data/lib/prawn/document/bounding_box.rb +85 -42
  8. data/lib/prawn/document/column_box.rb +21 -11
  9. data/lib/prawn/document/internals.rb +40 -147
  10. data/lib/prawn/document/span.rb +25 -17
  11. data/lib/prawn/document.rb +286 -245
  12. data/lib/prawn/encoding.rb +68 -101
  13. data/lib/prawn/errors.rb +47 -43
  14. data/lib/prawn/font.rb +204 -155
  15. data/lib/prawn/font_metric_cache.rb +25 -21
  16. data/lib/prawn/fonts/afm.rb +292 -0
  17. data/lib/prawn/{font → fonts}/dfont.rb +7 -13
  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 +142 -80
  21. data/lib/prawn/graphics/blend_mode.rb +65 -0
  22. data/lib/prawn/graphics/cap_style.rb +6 -5
  23. data/lib/prawn/graphics/color.rb +47 -44
  24. data/lib/prawn/graphics/dash.rb +30 -13
  25. data/lib/prawn/graphics/join_style.rb +13 -6
  26. data/lib/prawn/graphics/patterns.rb +221 -90
  27. data/lib/prawn/graphics/transformation.rb +21 -12
  28. data/lib/prawn/graphics/transparency.rb +21 -17
  29. data/lib/prawn/graphics.rb +155 -128
  30. data/lib/prawn/{layout/grid.rb → grid.rb} +110 -47
  31. data/lib/prawn/image_handler.rb +16 -2
  32. data/lib/prawn/images/image.rb +4 -2
  33. data/lib/prawn/images/jpg.rb +39 -30
  34. data/lib/prawn/images/png.rb +132 -169
  35. data/lib/prawn/images.rb +70 -62
  36. data/lib/prawn/measurement_extensions.rb +15 -10
  37. data/lib/prawn/measurements.rb +22 -23
  38. data/lib/prawn/outline.rb +301 -13
  39. data/lib/prawn/repeater.rb +19 -17
  40. data/lib/prawn/security/arcfour.rb +54 -0
  41. data/lib/prawn/security.rb +108 -86
  42. data/lib/prawn/soft_mask.rb +40 -41
  43. data/lib/prawn/stamp.rb +29 -12
  44. data/lib/prawn/text/box.rb +27 -29
  45. data/lib/prawn/text/formatted/arranger.rb +110 -67
  46. data/lib/prawn/text/formatted/box.rb +233 -165
  47. data/lib/prawn/text/formatted/fragment.rb +27 -27
  48. data/lib/prawn/text/formatted/line_wrap.rb +137 -97
  49. data/lib/prawn/text/formatted/parser.rb +149 -127
  50. data/lib/prawn/text/formatted/wrap.rb +57 -37
  51. data/lib/prawn/text/formatted.rb +6 -4
  52. data/lib/prawn/text.rb +105 -73
  53. data/lib/prawn/transformation_stack.rb +44 -0
  54. data/lib/prawn/utilities.rb +11 -21
  55. data/lib/prawn/version.rb +5 -0
  56. data/lib/prawn/view.rb +101 -0
  57. data/lib/prawn.rb +42 -68
  58. data/{data/images/fractal.jpg → manual/absolute_position.pdf} +0 -0
  59. data/manual/basic_concepts/adding_pages.rb +9 -10
  60. data/manual/basic_concepts/basic_concepts.rb +33 -24
  61. data/manual/basic_concepts/creation.rb +10 -11
  62. data/manual/basic_concepts/cursor.rb +9 -10
  63. data/manual/basic_concepts/measurement.rb +10 -11
  64. data/manual/basic_concepts/origin.rb +8 -9
  65. data/manual/basic_concepts/other_cursor_helpers.rb +17 -18
  66. data/manual/basic_concepts/view.rb +48 -0
  67. data/manual/bounding_box/bounding_box.rb +31 -29
  68. data/manual/bounding_box/bounds.rb +17 -18
  69. data/manual/bounding_box/canvas.rb +8 -9
  70. data/manual/bounding_box/creation.rb +8 -9
  71. data/manual/bounding_box/indentation.rb +22 -23
  72. data/manual/bounding_box/nesting.rb +32 -25
  73. data/manual/bounding_box/russian_boxes.rb +19 -19
  74. data/manual/bounding_box/stretchy.rb +18 -20
  75. data/manual/contents.rb +35 -0
  76. data/manual/cover.rb +43 -0
  77. data/manual/document_and_page_options/background.rb +16 -14
  78. data/manual/document_and_page_options/document_and_page_options.rb +26 -23
  79. data/manual/document_and_page_options/metadata.rb +21 -19
  80. data/manual/document_and_page_options/page_margins.rb +20 -22
  81. data/manual/document_and_page_options/page_size.rb +15 -15
  82. data/manual/document_and_page_options/print_scaling.rb +23 -0
  83. data/manual/example_helper.rb +5 -408
  84. data/manual/graphics/blend_mode.rb +52 -0
  85. data/manual/graphics/circle_and_ellipse.rb +8 -9
  86. data/manual/graphics/color.rb +11 -13
  87. data/manual/graphics/common_lines.rb +13 -12
  88. data/manual/graphics/fill_and_stroke.rb +10 -11
  89. data/manual/graphics/fill_rules.rb +13 -12
  90. data/manual/graphics/gradients.rb +28 -22
  91. data/manual/graphics/graphics.rb +52 -46
  92. data/manual/graphics/helper.rb +20 -10
  93. data/manual/graphics/line_width.rb +13 -12
  94. data/manual/graphics/lines_and_curves.rb +13 -14
  95. data/manual/graphics/polygon.rb +10 -12
  96. data/manual/graphics/rectangle.rb +7 -8
  97. data/manual/graphics/rotate.rb +9 -12
  98. data/manual/graphics/scale.rb +19 -18
  99. data/manual/graphics/soft_masks.rb +5 -7
  100. data/manual/graphics/stroke_cap.rb +10 -11
  101. data/manual/graphics/stroke_dash.rb +16 -17
  102. data/manual/graphics/stroke_join.rb +10 -11
  103. data/manual/graphics/translate.rb +13 -13
  104. data/manual/graphics/transparency.rb +11 -13
  105. data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +23 -25
  106. data/manual/images/absolute_position.rb +9 -10
  107. data/manual/images/fit.rb +9 -10
  108. data/manual/images/horizontal.rb +13 -14
  109. data/manual/images/images.rb +31 -30
  110. data/manual/images/plain_image.rb +6 -7
  111. data/manual/images/scale.rb +12 -13
  112. data/manual/images/vertical.rb +19 -17
  113. data/manual/images/width_and_height.rb +13 -14
  114. data/manual/layout/boxes.rb +14 -15
  115. data/manual/layout/content.rb +12 -13
  116. data/manual/layout/layout.rb +19 -20
  117. data/manual/layout/simple_grid.rb +8 -9
  118. data/manual/outline/add_subsection_to.rb +26 -27
  119. data/manual/outline/insert_section_after.rb +19 -20
  120. data/manual/outline/outline.rb +23 -22
  121. data/manual/outline/sections_and_pages.rb +24 -25
  122. data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
  123. data/manual/repeatable_content/page_numbering.rb +20 -19
  124. data/manual/repeatable_content/repeatable_content.rb +26 -22
  125. data/manual/repeatable_content/repeater.rb +18 -19
  126. data/manual/repeatable_content/stamp.rb +18 -19
  127. data/manual/security/encryption.rb +8 -11
  128. data/manual/security/permissions.rb +20 -15
  129. data/manual/security/security.rb +20 -20
  130. data/manual/table.rb +16 -0
  131. data/manual/text/alignment.rb +17 -18
  132. data/manual/text/color.rb +13 -13
  133. data/manual/text/column_box.rb +10 -12
  134. data/manual/text/fallback_fonts.rb +29 -25
  135. data/manual/text/font.rb +17 -18
  136. data/manual/text/font_size.rb +21 -22
  137. data/manual/text/font_style.rb +12 -10
  138. data/manual/text/formatted_callbacks.rb +36 -26
  139. data/manual/text/formatted_text.rb +41 -34
  140. data/manual/text/free_flowing_text.rb +28 -29
  141. data/manual/text/inline.rb +23 -26
  142. data/manual/text/kerning_and_character_spacing.rb +20 -21
  143. data/manual/text/leading.rb +10 -11
  144. data/manual/text/line_wrapping.rb +40 -21
  145. data/manual/text/paragraph_indentation.rb +17 -12
  146. data/manual/text/positioned_text.rb +19 -20
  147. data/manual/text/registering_families.rb +33 -30
  148. data/manual/text/rendering_and_color.rb +11 -12
  149. data/manual/text/right_to_left_text.rb +31 -20
  150. data/manual/text/rotation.rb +36 -27
  151. data/manual/text/single_usage.rb +13 -14
  152. data/manual/text/text.rb +62 -62
  153. data/manual/text/text_box_excess.rb +22 -19
  154. data/manual/text/text_box_extensions.rb +21 -18
  155. data/manual/text/text_box_overflow.rb +28 -21
  156. data/manual/text/utf8.rb +16 -17
  157. data/manual/text/win_ansi_charset.rb +29 -26
  158. data/prawn.gemspec +45 -43
  159. data/spec/extensions/encoding_helpers.rb +4 -3
  160. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  161. data/spec/prawn/document/column_box_spec.rb +75 -0
  162. data/spec/prawn/document/security_spec.rb +176 -0
  163. data/spec/prawn/document_annotations_spec.rb +76 -0
  164. data/spec/prawn/document_destinations_spec.rb +15 -0
  165. data/spec/prawn/document_grid_spec.rb +99 -0
  166. data/spec/prawn/document_reference_spec.rb +27 -0
  167. data/spec/prawn/document_span_spec.rb +44 -0
  168. data/spec/prawn/document_spec.rb +805 -0
  169. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  170. data/spec/prawn/font_spec.rb +544 -0
  171. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  172. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  173. data/spec/prawn/graphics_spec.rb +872 -0
  174. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  175. data/spec/prawn/image_handler_spec.rb +53 -0
  176. data/spec/prawn/images/jpg_spec.rb +20 -0
  177. data/spec/prawn/images/png_spec.rb +283 -0
  178. data/spec/prawn/images_spec.rb +229 -0
  179. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  180. data/spec/prawn/outline_spec.rb +512 -0
  181. data/spec/prawn/repeater_spec.rb +166 -0
  182. data/spec/prawn/soft_mask_spec.rb +74 -0
  183. data/spec/prawn/stamp_spec.rb +173 -0
  184. data/spec/prawn/text/box_spec.rb +1110 -0
  185. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  186. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  187. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  188. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  189. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  190. data/spec/prawn/text_draw_text_spec.rb +150 -0
  191. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  192. data/spec/prawn/text_spacing_spec.rb +95 -0
  193. data/spec/prawn/text_spec.rb +603 -0
  194. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  195. data/spec/prawn/transformation_stack_spec.rb +66 -0
  196. data/spec/prawn/view_spec.rb +63 -0
  197. data/spec/prawn_manual_spec.rb +35 -0
  198. data/spec/spec_helper.rb +22 -21
  199. data.tar.gz.sig +0 -0
  200. metadata +168 -307
  201. metadata.gz.sig +0 -0
  202. data/README.md +0 -109
  203. data/data/encodings/win_ansi.txt +0 -29
  204. data/data/images/16bit.alpha +0 -0
  205. data/data/images/16bit.dat +0 -0
  206. data/data/images/16bit.png +0 -0
  207. data/data/images/arrow.png +0 -0
  208. data/data/images/arrow2.png +0 -0
  209. data/data/images/barcode_issue.png +0 -0
  210. data/data/images/dice.alpha +0 -0
  211. data/data/images/dice.dat +0 -0
  212. data/data/images/dice.png +0 -0
  213. data/data/images/dice_interlaced.png +0 -0
  214. data/data/images/indexed_color.dat +0 -0
  215. data/data/images/indexed_color.png +0 -0
  216. data/data/images/letterhead.jpg +0 -0
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.dat +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/lib/pdf/core/annotations.rb +0 -60
  244. data/lib/pdf/core/byte_string.rb +0 -9
  245. data/lib/pdf/core/destinations.rb +0 -90
  246. data/lib/pdf/core/document_state.rb +0 -78
  247. data/lib/pdf/core/filter_list.rb +0 -51
  248. data/lib/pdf/core/filters.rb +0 -36
  249. data/lib/pdf/core/graphics_state.rb +0 -68
  250. data/lib/pdf/core/literal_string.rb +0 -16
  251. data/lib/pdf/core/name_tree.rb +0 -177
  252. data/lib/pdf/core/object_store.rb +0 -320
  253. data/lib/pdf/core/outline.rb +0 -315
  254. data/lib/pdf/core/page.rb +0 -212
  255. data/lib/pdf/core/page_geometry.rb +0 -126
  256. data/lib/pdf/core/pdf_object.rb +0 -124
  257. data/lib/pdf/core/reference.rb +0 -103
  258. data/lib/pdf/core/stream.rb +0 -98
  259. data/lib/pdf/core/text.rb +0 -275
  260. data/lib/pdf/core.rb +0 -35
  261. data/lib/prawn/compatibility.rb +0 -91
  262. data/lib/prawn/document/graphics_state.rb +0 -73
  263. data/lib/prawn/document/snapshot.rb +0 -89
  264. data/lib/prawn/font/afm.rb +0 -203
  265. data/lib/prawn/layout.rb +0 -20
  266. data/lib/prawn/table/cell/image.rb +0 -70
  267. data/lib/prawn/table/cell/in_table.rb +0 -27
  268. data/lib/prawn/table/cell/span_dummy.rb +0 -92
  269. data/lib/prawn/table/cell/subtable.rb +0 -65
  270. data/lib/prawn/table/cell/text.rb +0 -153
  271. data/lib/prawn/table/cell.rb +0 -770
  272. data/lib/prawn/table/cells.rb +0 -295
  273. data/lib/prawn/table.rb +0 -643
  274. data/manual/example_file.rb +0 -116
  275. data/manual/example_package.rb +0 -53
  276. data/manual/example_section.rb +0 -46
  277. data/manual/manual/cover.rb +0 -35
  278. data/manual/manual/foreword.rb +0 -85
  279. data/manual/manual/manual.rb +0 -35
  280. data/manual/syntax_highlight.rb +0 -52
  281. data/manual/table/basic_block.rb +0 -53
  282. data/manual/table/before_rendering_page.rb +0 -26
  283. data/manual/table/cell_border_lines.rb +0 -24
  284. data/manual/table/cell_borders_and_bg.rb +0 -31
  285. data/manual/table/cell_dimensions.rb +0 -30
  286. data/manual/table/cell_text.rb +0 -38
  287. data/manual/table/column_widths.rb +0 -30
  288. data/manual/table/content_and_subtables.rb +0 -39
  289. data/manual/table/creation.rb +0 -27
  290. data/manual/table/filtering.rb +0 -36
  291. data/manual/table/flow_and_header.rb +0 -17
  292. data/manual/table/image_cells.rb +0 -33
  293. data/manual/table/position.rb +0 -29
  294. data/manual/table/row_colors.rb +0 -20
  295. data/manual/table/span.rb +0 -30
  296. data/manual/table/style.rb +0 -22
  297. data/manual/table/table.rb +0 -52
  298. data/manual/table/width.rb +0 -27
  299. data/manual/templates/full_template.rb +0 -25
  300. data/manual/templates/page_template.rb +0 -48
  301. data/manual/templates/templates.rb +0 -27
  302. data/manual/text/group.rb +0 -29
  303. data/spec/acceptance/png.rb +0 -23
  304. data/spec/annotations_spec.rb +0 -74
  305. data/spec/bounding_box_spec.rb +0 -493
  306. data/spec/cell_spec.rb +0 -628
  307. data/spec/column_box_spec.rb +0 -33
  308. data/spec/destinations_spec.rb +0 -15
  309. data/spec/document_spec.rb +0 -761
  310. data/spec/extensions/mocha.rb +0 -44
  311. data/spec/filters_spec.rb +0 -34
  312. data/spec/font_metric_cache_spec.rb +0 -52
  313. data/spec/font_spec.rb +0 -464
  314. data/spec/formatted_text_arranger_spec.rb +0 -421
  315. data/spec/formatted_text_box_spec.rb +0 -650
  316. data/spec/formatted_text_fragment_spec.rb +0 -298
  317. data/spec/graphics_spec.rb +0 -651
  318. data/spec/grid_spec.rb +0 -85
  319. data/spec/image_handler_spec.rb +0 -42
  320. data/spec/images_spec.rb +0 -157
  321. data/spec/inline_formatted_text_parser_spec.rb +0 -564
  322. data/spec/jpg_spec.rb +0 -25
  323. data/spec/line_wrap_spec.rb +0 -333
  324. data/spec/measurement_units_spec.rb +0 -23
  325. data/spec/name_tree_spec.rb +0 -112
  326. data/spec/object_store_spec.rb +0 -170
  327. data/spec/outline_spec.rb +0 -448
  328. data/spec/pdf_object_spec.rb +0 -172
  329. data/spec/png_spec.rb +0 -240
  330. data/spec/reference_spec.rb +0 -82
  331. data/spec/repeater_spec.rb +0 -158
  332. data/spec/security_spec.rb +0 -158
  333. data/spec/snapshot_spec.rb +0 -186
  334. data/spec/soft_mask_spec.rb +0 -117
  335. data/spec/span_spec.rb +0 -44
  336. data/spec/stamp_spec.rb +0 -158
  337. data/spec/stream_spec.rb +0 -58
  338. data/spec/stroke_styles_spec.rb +0 -211
  339. data/spec/table/span_dummy_spec.rb +0 -17
  340. data/spec/table_spec.rb +0 -1355
  341. data/spec/template_spec.rb +0 -351
  342. data/spec/text_at_spec.rb +0 -130
  343. data/spec/text_box_spec.rb +0 -1030
  344. data/spec/text_rendering_mode_spec.rb +0 -45
  345. data/spec/text_spacing_spec.rb +0 -93
  346. data/spec/text_spec.rb +0 -425
  347. data/spec/text_with_inline_formatting_spec.rb +0 -35
  348. data/spec/transparency_spec.rb +0 -89
@@ -1,5 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
+ # frozen_string_literal: true
4
+
3
5
  # png.rb : Extracts the data from a PNG that is needed for embedding
4
6
  #
5
7
  # Based on some similar code in PDF::Writer by Austin Ziegler
@@ -9,14 +11,14 @@
9
11
  # This is free software. Please see the LICENSE and COPYING files for details.
10
12
 
11
13
  require 'stringio'
12
- require 'enumerator'
13
-
14
14
  module Prawn
15
15
  module Images
16
16
  # A convenience class that wraps the logic for extracting the parts
17
17
  # of a PNG image that we need to embed them in a PDF
18
18
  #
19
19
  class PNG < Image
20
+ # @group Extension API
21
+
20
22
  attr_reader :palette, :img_data, :transparency
21
23
  attr_reader :width, :height, :bits
22
24
  attr_reader :color_type, :compression_method, :filter_method
@@ -24,7 +26,7 @@ module Prawn
24
26
  attr_accessor :scaled_width, :scaled_height
25
27
 
26
28
  def self.can_render?(image_blob)
27
- image_blob[0, 8].unpack("C*") == [137, 80, 78, 71, 13, 10, 26, 10]
29
+ image_blob[0, 8].unpack('C*') == [137, 80, 78, 71, 13, 10, 26, 10]
28
30
  end
29
31
 
30
32
  # Process a new PNG image
@@ -32,30 +34,31 @@ module Prawn
32
34
  # <tt>data</tt>:: A binary string of PNG data
33
35
  #
34
36
  def initialize(data)
37
+ super()
35
38
  data = StringIO.new(data.dup)
36
39
 
37
- data.read(8) # Skip the default header
40
+ data.read(8) # Skip the default header
38
41
 
39
- @palette = ""
40
- @img_data = ""
42
+ @palette = +''
43
+ @img_data = +''
41
44
  @transparency = {}
42
45
 
43
46
  loop do
44
- chunk_size = data.read(4).unpack("N")[0]
45
- section = data.read(4)
47
+ chunk_size = data.read(4).unpack1('N')
48
+ section = data.read(4)
46
49
  case section
47
50
  when 'IHDR'
48
51
  # we can grab other interesting values from here (like width,
49
52
  # height, etc)
50
- values = data.read(chunk_size).unpack("NNCCCCC")
53
+ values = data.read(chunk_size).unpack('NNCCCCC')
51
54
 
52
- @width = values[0]
53
- @height = values[1]
54
- @bits = values[2]
55
- @color_type = values[3]
55
+ @width = values[0]
56
+ @height = values[1]
57
+ @bits = values[2]
58
+ @color_type = values[3]
56
59
  @compression_method = values[4]
57
- @filter_method = values[5]
58
- @interlace_method = values[6]
60
+ @filter_method = values[5]
61
+ @interlace_method = values[6]
59
62
  when 'PLTE'
60
63
  @palette << data.read(chunk_size)
61
64
  when 'IDAT'
@@ -66,21 +69,15 @@ module Prawn
66
69
  @transparency = {}
67
70
  case @color_type
68
71
  when 3
69
- # Indexed colour, RGB. Each byte in this chunk is an alpha for
70
- # the palette index in the PLTE ("palette") chunk up until the
71
- # last non-opaque entry. Set up an array, stretching over all
72
- # palette entries which will be 0 (opaque) or 1 (transparent).
73
- @transparency[:indexed] = data.read(chunk_size).unpack("C*")
74
- short = 255 - @transparency[:indexed].size
75
- @transparency[:indexed] += ([255] * short) if short > 0
72
+ @transparency[:palette] = data.read(chunk_size).unpack('C*')
76
73
  when 0
77
74
  # Greyscale. Corresponding to entries in the PLTE chunk.
78
75
  # Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
79
- grayval = data.read(chunk_size).unpack("n").first
76
+ grayval = data.read(chunk_size).unpack1('n')
80
77
  @transparency[:grayscale] = grayval
81
78
  when 2
82
79
  # True colour with proper alpha channel.
83
- @transparency[:rgb] = data.read(chunk_size).unpack("nnn")
80
+ @transparency[:rgb] = data.read(chunk_size).unpack('nnn')
84
81
  end
85
82
  when 'IEND'
86
83
  # we've got everything we need, exit the loop
@@ -90,7 +87,7 @@ module Prawn
90
87
  data.seek(data.pos + chunk_size)
91
88
  end
92
89
 
93
- data.read(4) # Skip the CRC
90
+ data.read(4) # Skip the CRC
94
91
  end
95
92
 
96
93
  @img_data = Zlib::Inflate.inflate(@img_data)
@@ -99,21 +96,11 @@ module Prawn
99
96
  # number of color components to each pixel
100
97
  #
101
98
  def colors
102
- case self.color_type
99
+ case color_type
103
100
  when 0, 3, 4
104
- return 1
101
+ 1
105
102
  when 2, 6
106
- return 3
107
- end
108
- end
109
-
110
- # number of bits used per pixel
111
- #
112
- def pixel_bitlength
113
- if alpha_channel?
114
- self.bits * (self.colors + 1)
115
- else
116
- self.bits * self.colors
103
+ 3
117
104
  end
118
105
  end
119
106
 
@@ -121,18 +108,20 @@ module Prawn
121
108
  # where it's required.
122
109
  #
123
110
  def split_alpha_channel!
124
- unfilter_image_data if alpha_channel?
111
+ if alpha_channel?
112
+ if color_type == 3
113
+ generate_alpha_channel
114
+ else
115
+ split_image_data
116
+ end
117
+ end
125
118
  end
126
119
 
127
120
  def alpha_channel?
128
- @color_type == 4 || @color_type == 6
129
- end
121
+ return true if color_type == 4 || color_type == 6
122
+ return @transparency.any? if color_type == 3
130
123
 
131
- # Adobe Reader can't handle 16-bit png channels -- chop off the second
132
- # byte (least significant)
133
- #
134
- def alpha_channel_bits
135
- 8
124
+ false
136
125
  end
137
126
 
138
127
  # Build a PDF object representing this image in +document+, and return
@@ -170,28 +159,24 @@ module Prawn
170
159
 
171
160
  # build the image dict
172
161
  obj = document.ref!(
173
- :Type => :XObject,
174
- :Subtype => :Image,
175
- :Height => height,
176
- :Width => width,
177
- :BitsPerComponent => bits
162
+ Type: :XObject,
163
+ Subtype: :Image,
164
+ Height: height,
165
+ Width: width,
166
+ BitsPerComponent: bits
178
167
  )
179
168
 
180
169
  # append the actual image data to the object as a stream
181
170
  obj << img_data
182
171
 
183
- if alpha_channel
184
- obj.stream.compress!
185
- else
186
- obj.stream.filters << {
187
- :FlateDecode => {
188
- :Predictor => 15,
189
- :Colors => colors,
190
- :BitsPerComponent => bits,
191
- :Columns => width
192
- }
172
+ obj.stream.filters << {
173
+ FlateDecode: {
174
+ Predictor: 15,
175
+ Colors: colors,
176
+ BitsPerComponent: bits,
177
+ Columns: width
193
178
  }
194
- end
179
+ }
195
180
 
196
181
  # sort out the colours of the image
197
182
  if palette.empty?
@@ -202,10 +187,12 @@ module Prawn
202
187
  palette_obj << palette
203
188
 
204
189
  # build the color space array for the image
205
- obj.data[:ColorSpace] = [:Indexed,
206
- :DeviceRGB,
207
- (palette.size / 3) -1,
208
- palette_obj]
190
+ obj.data[:ColorSpace] = [
191
+ :Indexed,
192
+ :DeviceRGB,
193
+ (palette.size / 3) - 1,
194
+ palette_obj
195
+ ]
209
196
  end
210
197
 
211
198
  # *************************************
@@ -226,29 +213,33 @@ module Prawn
226
213
  # - An array with N elements, where N is two times the number of color
227
214
  # components.
228
215
  rgb = transparency[:rgb]
229
- obj.data[:Mask] = rgb.collect { |x| [x,x] }.flatten
230
- elsif transparency[:indexed]
231
- # TODO: broken. I was attempting to us Color Key Masking, but I think
232
- # we need to construct an SMask i think. Maybe do it inside
233
- # the PNG class, and store it in alpha_channel
234
- #obj.data[:Mask] = transparency[:indexed]
216
+ obj.data[:Mask] = rgb.map { |x| [x, x] }.flatten
235
217
  end
236
218
 
237
- # For PNG color types 4 and 6, the transparency data is stored as a alpha
238
- # channel mixed in with the main image data. The PNG class seperates
239
- # it out for us and makes it available via the alpha_channel attribute
219
+ # For PNG color types 4 and 6, the transparency data is stored as
220
+ # a alpha channel mixed in with the main image data. The PNG class
221
+ # seperates it out for us and makes it available via the alpha_channel
222
+ # attribute
240
223
  if alpha_channel?
241
224
  smask_obj = document.ref!(
242
- :Type => :XObject,
243
- :Subtype => :Image,
244
- :Height => height,
245
- :Width => width,
246
- :BitsPerComponent => alpha_channel_bits,
247
- :ColorSpace => :DeviceGray,
248
- :Decode => [0, 1]
225
+ Type: :XObject,
226
+ Subtype: :Image,
227
+ Height: height,
228
+ Width: width,
229
+ BitsPerComponent: bits,
230
+ ColorSpace: :DeviceGray,
231
+ Decode: [0, 1]
249
232
  )
250
233
  smask_obj.stream << alpha_channel
251
- smask_obj.stream.compress!
234
+
235
+ smask_obj.stream.filters << {
236
+ FlateDecode: {
237
+ Predictor: 15,
238
+ Colors: 1,
239
+ BitsPerComponent: bits,
240
+ Columns: width
241
+ }
242
+ }
252
243
  obj.data[:SMask] = smask_obj
253
244
  end
254
245
 
@@ -270,97 +261,69 @@ module Prawn
270
261
 
271
262
  private
272
263
 
273
- def unfilter_image_data
274
- data = @img_data.dup
275
-
276
- @img_data = ""
277
- @alpha_channel = ""
278
-
279
- pixel_bytes = pixel_bitlength / 8
280
- scanline_length = pixel_bytes * self.width + 1
281
- row = 0
282
- pixels = []
283
- row_data = [] # reused for each row of the image
284
- paeth, pa, pb, pc = nil
285
-
286
- data.bytes.each do |byte|
287
- # accumulate a whole scanline of bytes, and then process it all at once
288
- # we could do this with Enumerable#each_slice, but it allocates memory,
289
- # and we are trying to avoid that
290
- row_data << byte
291
- next if row_data.length < scanline_length
292
-
293
- filter = row_data.shift
294
- case filter
295
- when 0 # None
296
- when 1 # Sub
297
- row_data.each_with_index do |row_byte, index|
298
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
299
- row_data[index] = (row_byte + left) % 256
300
- end
301
- when 2 # Up
302
- row_data.each_with_index do |row_byte, index|
303
- col = (index / pixel_bytes).floor
304
- upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
305
- row_data[index] = (upper + row_byte) % 256
306
- end
307
- when 3 # Average
308
- row_data.each_with_index do |row_byte, index|
309
- col = (index / pixel_bytes).floor
310
- upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
311
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
264
+ def split_image_data
265
+ alpha_bytes = bits / 8
266
+ color_bytes = colors * bits / 8
312
267
 
313
- row_data[index] = (row_byte + ((left + upper)/2).floor) % 256
314
- end
315
- when 4 # Paeth
316
- left = upper = upper_left = nil
317
- row_data.each_with_index do |row_byte, index|
318
- col = (index / pixel_bytes).floor
319
-
320
- left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
321
- if row.zero?
322
- upper = upper_left = 0
323
- else
324
- upper = pixels[row-1][col][index % pixel_bytes]
325
- upper_left = col.zero? ? 0 :
326
- pixels[row-1][col-1][index % pixel_bytes]
327
- end
328
-
329
- p = left + upper - upper_left
330
- pa = (p - left).abs
331
- pb = (p - upper).abs
332
- pc = (p - upper_left).abs
333
-
334
- paeth = if pa <= pb && pa <= pc
335
- left
336
- elsif pb <= pc
337
- upper
338
- else
339
- upper_left
340
- end
341
-
342
- row_data[index] = (row_byte + paeth) % 256
343
- end
344
- else
345
- raise ArgumentError, "Invalid filter algorithm #{filter}"
346
- end
268
+ scanline_length = (color_bytes + alpha_bytes) * width + 1
269
+ scanlines = @img_data.bytesize / scanline_length
270
+ pixels = width * height
271
+
272
+ data = StringIO.new(@img_data)
273
+ data.binmode
274
+
275
+ color_data = [0x00].pack('C') * (pixels * color_bytes + scanlines)
276
+ color = StringIO.new(color_data)
277
+ color.binmode
278
+
279
+ @alpha_channel = [0x00].pack('C') * (pixels * alpha_bytes + scanlines)
280
+ alpha = StringIO.new(@alpha_channel)
281
+ alpha.binmode
282
+
283
+ scanlines.times do |line|
284
+ data.seek(line * scanline_length)
285
+
286
+ filter = data.getbyte
287
+
288
+ color.putc filter
289
+ alpha.putc filter
347
290
 
348
- s = []
349
- row_data.each_slice pixel_bytes do |slice|
350
- s << slice
291
+ width.times do
292
+ color.write data.read(color_bytes)
293
+ alpha.write data.read(alpha_bytes)
351
294
  end
352
- pixels << s
353
- row += 1
354
- row_data.clear
355
295
  end
356
296
 
357
- # convert the pixel data to separate strings for colours and alpha
358
- color_byte_size = self.colors * self.bits / 8
359
- alpha_byte_size = alpha_channel_bits / 8
360
- pixels.each do |this_row|
361
- this_row.each do |pixel|
362
- @img_data << pixel[0, color_byte_size].pack("C*")
363
- @alpha_channel << pixel[color_byte_size, alpha_byte_size].pack("C*")
297
+ @img_data = color_data
298
+ end
299
+
300
+ def generate_alpha_channel
301
+ alpha_palette = Hash.new(0xff)
302
+ 0.upto(palette.bytesize / 3) do |n|
303
+ alpha_palette[n] = @transparency[:palette][n] || 0xff
304
+ end
305
+
306
+ scanline_length = width + 1
307
+ scanlines = @img_data.bytesize / scanline_length
308
+ pixels = width * height
309
+
310
+ data = StringIO.new(@img_data)
311
+ data.binmode
312
+
313
+ @alpha_channel = [0x00].pack('C') * (pixels + scanlines)
314
+ alpha = StringIO.new(@alpha_channel)
315
+ alpha.binmode
316
+
317
+ scanlines.times do |line|
318
+ data.seek(line * scanline_length)
319
+
320
+ filter = data.getbyte
321
+
322
+ alpha.putc filter
323
+
324
+ width.times do
325
+ color = data.read(1).unpack1('C')
326
+ alpha.putc alpha_palette[color]
364
327
  end
365
328
  end
366
329
  end
data/lib/prawn/images.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
+
3
+ # frozen_string_literal: true
4
+
2
5
  # images.rb : Implements PDF image embedding
3
6
  #
4
7
  # Copyright April 2008, James Healy, Gregory Brown. All Rights Reserved.
@@ -9,28 +12,27 @@ require 'digest/sha1'
9
12
  require 'pathname'
10
13
 
11
14
  module Prawn
12
-
13
15
  module Images
16
+ # @group Stable API
17
+
14
18
  # Add the image at filename to the current page. Currently only
15
- # JPG and PNG files are supported.
16
- #
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:
20
- #
21
- # http://github.com/amberbit/prawn-fast-png
19
+ # JPG and PNG files are supported. (Note that processing PNG
20
+ # images with alpha channels can be processor and memory intensive.)
22
21
  #
23
22
  # Arguments:
24
- # <tt>file</tt>:: path to file or an object that responds to #read
23
+ # <tt>file</tt>:: path to file or an object that responds to #read and
24
+ # #rewind
25
25
  #
26
26
  # Options:
27
- # <tt>:at</tt>:: an array [x,y] with the location of the top left corner of the image.
27
+ # <tt>:at</tt>:: an array [x,y] with the location of the top left corner of
28
+ # the image.
28
29
  # <tt>:position</tt>:: One of (:left, :center, :right) or an x-offset
29
- # <tt>:vposition</tt>:: One of (:top, :center, :center) or an y-offset
30
+ # <tt>:vposition</tt>:: One of (:top, :center, :bottom) or an y-offset
30
31
  # <tt>:height</tt>:: the height of the image [actual height of the image]
31
32
  # <tt>:width</tt>:: the width of the image [actual width of the image]
32
33
  # <tt>:scale</tt>:: scale the dimensions of the image proportionally
33
- # <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit inside [width,height]
34
+ # <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit
35
+ # inside [width,height]
34
36
  #
35
37
  # Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do
36
38
  # pigs = "#{Prawn::DATADIR}/images/pigs.jpg"
@@ -56,16 +58,18 @@ module Prawn
56
58
  # require "open-uri"
57
59
  #
58
60
  # Prawn::Document.generate("remote_images.pdf") do
59
- # image open("http://prawn.majesticseacreature.com/media/prawn_logo.png")
61
+ # image open("http://prawnpdf.org/media/prawn_logo.png")
60
62
  # end
61
63
  #
62
64
  # This method returns an image info object which can be used to check the
63
65
  # dimensions of an image object if needed.
64
66
  # (See also: Prawn::Images::PNG , Prawn::Images::JPG)
65
67
  #
66
- def image(file, options={})
67
- Prawn.verify_options [:at, :position, :vposition, :height,
68
- :width, :scale, :fit], options
68
+ def image(file, options = {})
69
+ Prawn.verify_options(
70
+ %i[at position vposition height width scale fit],
71
+ options
72
+ )
69
73
 
70
74
  pdf_obj, info = build_image_object(file)
71
75
  embed_image(pdf_obj, info, options)
@@ -76,9 +80,9 @@ module Prawn
76
80
  # Builds an info object (Prawn::Images::*) and a PDF reference representing
77
81
  # the given image. Return a pair: [pdf_obj, info].
78
82
  #
83
+ # @private
79
84
  def build_image_object(file)
80
- io = verify_and_open_image(file)
81
- image_content = io.read
85
+ image_content = verify_and_read_image(file)
82
86
  image_sha1 = Digest::SHA1.hexdigest(image_content)
83
87
 
84
88
  # if this image has already been embedded, just reuse it
@@ -90,11 +94,13 @@ module Prawn
90
94
  info = Prawn.image_handler.find(image_content).new(image_content)
91
95
 
92
96
  # Bump PDF version if the image requires it
93
- min_version(info.min_pdf_version) if info.respond_to?(:min_pdf_version)
97
+ if info.respond_to?(:min_pdf_version)
98
+ renderer.min_version(info.min_pdf_version)
99
+ end
94
100
 
95
101
  # Add the image to the PDF and register it in case we see it again.
96
102
  image_obj = info.build_pdf_object(self)
97
- image_registry[image_sha1] = {:obj => image_obj, :info => info}
103
+ image_registry[image_sha1] = { obj: image_obj, info: info }
98
104
  end
99
105
 
100
106
  [image_obj, info]
@@ -105,30 +111,30 @@ module Prawn
105
111
  # build_image_object), embed the image according to the <tt>options</tt>
106
112
  # given.
107
113
  #
114
+ # @private
108
115
  def embed_image(pdf_obj, info, options)
109
116
  # find where the image will be placed and how big it will be
110
- w,h = info.calc_image_dimensions(options)
117
+ w, h = info.calc_image_dimensions(options)
111
118
 
112
119
  if options[:at]
113
- x,y = map_to_absolute(options[:at])
120
+ x, y = map_to_absolute(options[:at])
114
121
  else
115
- x,y = image_position(w,h,options)
122
+ x, y = image_position(w, h, options)
116
123
  move_text_position h
117
124
  end
118
125
 
119
126
  # add a reference to the image object to the current page
120
127
  # resource list and give it a label
121
128
  label = "I#{next_image_id}"
122
- state.page.xobjects.merge!(label => pdf_obj)
129
+ state.page.xobjects[label] = pdf_obj
123
130
 
124
- # add the image to the current page
125
- instruct = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
126
- add_content instruct % [ w, h, x, y - h, label ]
131
+ cm_params = PDF::Core.real_params([w, 0, 0, h, x, y - h])
132
+ renderer.add_content("\nq\n#{cm_params} cm\n/#{label} Do\nQ")
127
133
  end
128
134
 
129
135
  private
130
136
 
131
- def verify_and_open_image(io_or_path)
137
+ def verify_and_read_image(io_or_path)
132
138
  # File or IO
133
139
  if io_or_path.respond_to?(:rewind)
134
140
  io = io_or_path
@@ -138,54 +144,56 @@ module Prawn
138
144
  # read the file as binary so the size is calculated correctly
139
145
  # guard binmode because some objects acting io-like don't implement it
140
146
  io.binmode if io.respond_to?(:binmode)
141
- return io
147
+ return io.read
142
148
  end
143
149
  # String or Pathname
144
150
  io_or_path = Pathname.new(io_or_path)
145
151
  raise ArgumentError, "#{io_or_path} not found" unless io_or_path.file?
146
- io = io_or_path.open('rb')
147
- io
152
+
153
+ io_or_path.binread
148
154
  end
149
155
 
150
- def image_position(w,h,options)
156
+ def image_position(width, height, options)
151
157
  options[:position] ||= :left
152
158
 
153
- y = case options[:vposition]
154
- when :top
155
- bounds.absolute_top
156
- when :center
157
- bounds.absolute_top - (bounds.height - h) / 2.0
158
- when :bottom
159
- bounds.absolute_bottom + h
160
- when Numeric
161
- bounds.absolute_top - options[:vposition]
162
- else
163
- determine_y_with_page_flow(h)
164
- end
165
-
166
- x = case options[:position]
167
- when :left
168
- bounds.left_side
169
- when :center
170
- bounds.left_side + (bounds.width - w) / 2.0
171
- when :right
172
- bounds.right_side - w
173
- when Numeric
174
- options[:position] + bounds.left_side
175
- end
176
-
177
- return [x,y]
159
+ y =
160
+ case options[:vposition]
161
+ when :top
162
+ bounds.absolute_top
163
+ when :center
164
+ bounds.absolute_top - (bounds.height - height) / 2.0
165
+ when :bottom
166
+ bounds.absolute_bottom + height
167
+ when Numeric
168
+ bounds.absolute_top - options[:vposition]
169
+ else
170
+ determine_y_with_page_flow(height)
171
+ end
172
+
173
+ x =
174
+ case options[:position]
175
+ when :left
176
+ bounds.left_side
177
+ when :center
178
+ bounds.left_side + (bounds.width - width) / 2.0
179
+ when :right
180
+ bounds.right_side - width
181
+ when Numeric
182
+ options[:position] + bounds.left_side
183
+ end
184
+
185
+ [x, y]
178
186
  end
179
187
 
180
- def determine_y_with_page_flow(h)
181
- if overruns_page?(h)
188
+ def determine_y_with_page_flow(height)
189
+ if overruns_page?(height)
182
190
  bounds.move_past_bottom
183
191
  end
184
- self.y
192
+ y
185
193
  end
186
194
 
187
- def overruns_page?(h)
188
- (self.y - h) < reference_bounds.absolute_bottom
195
+ def overruns_page?(height)
196
+ (y - height) < reference_bounds.absolute_bottom
189
197
  end
190
198
 
191
199
  def image_registry