prawn 0.15.0 → 1.0.0.rc1

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 (269) hide show
  1. data/COPYING +2 -2
  2. data/LICENSE +1 -1
  3. data/README.md +96 -0
  4. data/Rakefile +27 -30
  5. data/data/fonts/Action Man.dfont +0 -0
  6. data/data/fonts/Activa.ttf +0 -0
  7. data/data/fonts/Chalkboard.ttf +0 -0
  8. data/data/fonts/DejaVuSans.ttf +0 -0
  9. data/data/fonts/Dustismo_Roman.ttf +0 -0
  10. data/data/fonts/comicsans.ttf +0 -0
  11. data/data/fonts/gkai00mp.ttf +0 -0
  12. data/data/images/16bit.alpha +0 -0
  13. data/data/images/16bit.dat +0 -0
  14. data/data/images/dice.alpha +0 -0
  15. data/data/images/dice.dat +0 -0
  16. data/data/images/page_white_text.alpha +0 -0
  17. data/data/images/page_white_text.dat +0 -0
  18. data/data/images/rails.dat +0 -0
  19. data/data/images/rails.png +0 -0
  20. data/data/pdfs/nested_pages.pdf +13 -13
  21. data/lib/prawn.rb +21 -85
  22. data/lib/prawn/compatibility.rb +51 -0
  23. data/lib/prawn/core.rb +85 -0
  24. data/lib/prawn/core/annotations.rb +61 -0
  25. data/lib/prawn/core/byte_string.rb +9 -0
  26. data/lib/prawn/core/destinations.rb +90 -0
  27. data/lib/prawn/core/document_state.rb +78 -0
  28. data/lib/prawn/core/literal_string.rb +16 -0
  29. data/lib/prawn/core/name_tree.rb +177 -0
  30. data/lib/prawn/core/object_store.rb +264 -0
  31. data/lib/prawn/core/page.rb +215 -0
  32. data/lib/prawn/core/pdf_object.rb +108 -0
  33. data/lib/prawn/core/reference.rb +115 -0
  34. data/lib/prawn/core/text.rb +268 -0
  35. data/lib/prawn/core/text/formatted/arranger.rb +294 -0
  36. data/lib/prawn/core/text/formatted/line_wrap.rb +273 -0
  37. data/lib/prawn/core/text/formatted/wrap.rb +153 -0
  38. data/lib/prawn/document.rb +122 -155
  39. data/lib/prawn/document/bounding_box.rb +7 -36
  40. data/lib/prawn/document/column_box.rb +10 -38
  41. data/lib/prawn/document/graphics_state.rb +74 -11
  42. data/lib/prawn/document/internals.rb +23 -24
  43. data/lib/prawn/document/page_geometry.rb +136 -0
  44. data/lib/prawn/document/snapshot.rb +6 -7
  45. data/lib/prawn/document/span.rb +10 -12
  46. data/lib/prawn/encoding.rb +10 -9
  47. data/lib/prawn/errors.rb +30 -15
  48. data/lib/prawn/font.rb +104 -136
  49. data/lib/prawn/font/afm.rb +44 -46
  50. data/lib/prawn/font/dfont.rb +3 -4
  51. data/lib/prawn/font/ttf.rb +50 -31
  52. data/lib/prawn/graphics.rb +57 -302
  53. data/lib/prawn/graphics/cap_style.rb +3 -4
  54. data/lib/prawn/graphics/color.rb +5 -13
  55. data/lib/prawn/graphics/dash.rb +31 -53
  56. data/lib/prawn/graphics/gradient.rb +84 -0
  57. data/lib/prawn/graphics/join_style.rb +7 -9
  58. data/lib/prawn/graphics/transformation.rb +9 -10
  59. data/lib/prawn/graphics/transparency.rb +1 -3
  60. data/lib/prawn/images.rb +59 -69
  61. data/lib/prawn/images/image.rb +22 -6
  62. data/lib/prawn/images/jpg.rb +14 -20
  63. data/lib/prawn/images/png.rb +118 -61
  64. data/lib/prawn/layout.rb +15 -10
  65. data/lib/prawn/layout/grid.rb +54 -66
  66. data/lib/prawn/measurement_extensions.rb +6 -10
  67. data/lib/prawn/measurements.rb +21 -27
  68. data/lib/prawn/outline.rb +308 -6
  69. data/lib/prawn/repeater.rb +8 -10
  70. data/lib/prawn/security.rb +33 -55
  71. data/lib/prawn/security/arcfour.rb +0 -1
  72. data/lib/prawn/stamp.rb +3 -5
  73. data/lib/prawn/table.rb +60 -188
  74. data/lib/prawn/table/cell.rb +44 -272
  75. data/lib/prawn/table/cell/image.rb +3 -2
  76. data/lib/prawn/table/cell/in_table.rb +2 -4
  77. data/lib/prawn/table/cell/subtable.rb +2 -2
  78. data/lib/prawn/table/cell/text.rb +18 -41
  79. data/lib/prawn/table/cells.rb +48 -142
  80. data/lib/prawn/text.rb +25 -32
  81. data/lib/prawn/text/box.rb +6 -12
  82. data/lib/prawn/text/formatted.rb +4 -5
  83. data/lib/prawn/text/formatted/box.rb +59 -96
  84. data/lib/prawn/text/formatted/fragment.rb +23 -34
  85. data/lib/prawn/text/formatted/parser.rb +5 -15
  86. data/prawn.gemspec +13 -24
  87. data/spec/annotations_spec.rb +32 -16
  88. data/spec/bounding_box_spec.rb +17 -119
  89. data/spec/cell_spec.rb +42 -112
  90. data/spec/destinations_spec.rb +5 -5
  91. data/spec/document_spec.rb +111 -155
  92. data/spec/extensions/mocha.rb +0 -1
  93. data/spec/font_spec.rb +99 -149
  94. data/spec/formatted_text_arranger_spec.rb +43 -43
  95. data/spec/formatted_text_box_spec.rb +44 -43
  96. data/spec/formatted_text_fragment_spec.rb +8 -8
  97. data/spec/graphics_spec.rb +68 -151
  98. data/spec/grid_spec.rb +15 -26
  99. data/spec/images_spec.rb +30 -51
  100. data/spec/inline_formatted_text_parser_spec.rb +20 -69
  101. data/spec/jpg_spec.rb +4 -4
  102. data/spec/line_wrap_spec.rb +28 -28
  103. data/spec/measurement_units_spec.rb +6 -6
  104. data/spec/name_tree_spec.rb +112 -0
  105. data/spec/object_store_spec.rb +106 -17
  106. data/spec/outline_spec.rb +63 -103
  107. data/spec/pdf_object_spec.rb +170 -0
  108. data/spec/png_spec.rb +25 -25
  109. data/spec/reference_spec.rb +65 -8
  110. data/spec/repeater_spec.rb +10 -10
  111. data/spec/security_spec.rb +12 -44
  112. data/spec/snapshot_spec.rb +7 -7
  113. data/spec/span_spec.rb +15 -10
  114. data/spec/spec_helper.rb +8 -32
  115. data/spec/stamp_spec.rb +30 -29
  116. data/spec/stroke_styles_spec.rb +18 -36
  117. data/spec/table_spec.rb +111 -706
  118. data/spec/template_spec.rb +297 -0
  119. data/spec/text_at_spec.rb +33 -19
  120. data/spec/text_box_spec.rb +64 -100
  121. data/spec/text_rendering_mode_spec.rb +5 -5
  122. data/spec/text_spacing_spec.rb +4 -4
  123. data/spec/text_spec.rb +64 -84
  124. data/spec/transparency_spec.rb +5 -5
  125. metadata +290 -463
  126. checksums.yaml +0 -7
  127. data/.yardopts +0 -10
  128. data/Gemfile +0 -11
  129. data/data/images/16bit.color +0 -0
  130. data/data/images/dice.color +0 -0
  131. data/data/images/indexed_color.dat +0 -0
  132. data/data/images/indexed_color.png +0 -0
  133. data/data/images/page_white_text.color +0 -0
  134. data/lib/prawn/font_metric_cache.rb +0 -47
  135. data/lib/prawn/graphics/patterns.rb +0 -138
  136. data/lib/prawn/image_handler.rb +0 -36
  137. data/lib/prawn/soft_mask.rb +0 -96
  138. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  139. data/lib/prawn/table/column_width_calculator.rb +0 -61
  140. data/lib/prawn/text/formatted/arranger.rb +0 -290
  141. data/lib/prawn/text/formatted/line_wrap.rb +0 -266
  142. data/lib/prawn/text/formatted/wrap.rb +0 -150
  143. data/lib/prawn/utilities.rb +0 -46
  144. data/manual/basic_concepts/adding_pages.rb +0 -27
  145. data/manual/basic_concepts/basic_concepts.rb +0 -34
  146. data/manual/basic_concepts/creation.rb +0 -39
  147. data/manual/basic_concepts/cursor.rb +0 -33
  148. data/manual/basic_concepts/measurement.rb +0 -25
  149. data/manual/basic_concepts/origin.rb +0 -38
  150. data/manual/basic_concepts/other_cursor_helpers.rb +0 -40
  151. data/manual/bounding_box/bounding_box.rb +0 -39
  152. data/manual/bounding_box/bounds.rb +0 -49
  153. data/manual/bounding_box/canvas.rb +0 -24
  154. data/manual/bounding_box/creation.rb +0 -23
  155. data/manual/bounding_box/indentation.rb +0 -46
  156. data/manual/bounding_box/nesting.rb +0 -45
  157. data/manual/bounding_box/russian_boxes.rb +0 -40
  158. data/manual/bounding_box/stretchy.rb +0 -31
  159. data/manual/document_and_page_options/background.rb +0 -27
  160. data/manual/document_and_page_options/document_and_page_options.rb +0 -32
  161. data/manual/document_and_page_options/metadata.rb +0 -23
  162. data/manual/document_and_page_options/page_margins.rb +0 -38
  163. data/manual/document_and_page_options/page_size.rb +0 -34
  164. data/manual/document_and_page_options/print_scaling.rb +0 -20
  165. data/manual/example_file.rb +0 -111
  166. data/manual/example_helper.rb +0 -411
  167. data/manual/example_package.rb +0 -53
  168. data/manual/example_section.rb +0 -46
  169. data/manual/graphics/circle_and_ellipse.rb +0 -22
  170. data/manual/graphics/color.rb +0 -24
  171. data/manual/graphics/common_lines.rb +0 -30
  172. data/manual/graphics/fill_and_stroke.rb +0 -42
  173. data/manual/graphics/fill_rules.rb +0 -37
  174. data/manual/graphics/gradients.rb +0 -37
  175. data/manual/graphics/graphics.rb +0 -58
  176. data/manual/graphics/helper.rb +0 -24
  177. data/manual/graphics/line_width.rb +0 -35
  178. data/manual/graphics/lines_and_curves.rb +0 -41
  179. data/manual/graphics/polygon.rb +0 -29
  180. data/manual/graphics/rectangle.rb +0 -21
  181. data/manual/graphics/rotate.rb +0 -28
  182. data/manual/graphics/scale.rb +0 -41
  183. data/manual/graphics/soft_masks.rb +0 -46
  184. data/manual/graphics/stroke_cap.rb +0 -31
  185. data/manual/graphics/stroke_dash.rb +0 -48
  186. data/manual/graphics/stroke_join.rb +0 -30
  187. data/manual/graphics/translate.rb +0 -29
  188. data/manual/graphics/transparency.rb +0 -35
  189. data/manual/images/absolute_position.rb +0 -23
  190. data/manual/images/fit.rb +0 -21
  191. data/manual/images/horizontal.rb +0 -25
  192. data/manual/images/images.rb +0 -40
  193. data/manual/images/plain_image.rb +0 -18
  194. data/manual/images/scale.rb +0 -22
  195. data/manual/images/vertical.rb +0 -28
  196. data/manual/images/width_and_height.rb +0 -25
  197. data/manual/layout/boxes.rb +0 -27
  198. data/manual/layout/content.rb +0 -25
  199. data/manual/layout/layout.rb +0 -28
  200. data/manual/layout/simple_grid.rb +0 -23
  201. data/manual/manual/cover.rb +0 -36
  202. data/manual/manual/foreword.rb +0 -85
  203. data/manual/manual/how_to_read_this_manual.rb +0 -41
  204. data/manual/manual/manual.rb +0 -34
  205. data/manual/outline/add_subsection_to.rb +0 -61
  206. data/manual/outline/insert_section_after.rb +0 -47
  207. data/manual/outline/outline.rb +0 -32
  208. data/manual/outline/sections_and_pages.rb +0 -67
  209. data/manual/repeatable_content/page_numbering.rb +0 -54
  210. data/manual/repeatable_content/repeatable_content.rb +0 -31
  211. data/manual/repeatable_content/repeater.rb +0 -55
  212. data/manual/repeatable_content/stamp.rb +0 -41
  213. data/manual/security/encryption.rb +0 -31
  214. data/manual/security/permissions.rb +0 -38
  215. data/manual/security/security.rb +0 -28
  216. data/manual/syntax_highlight.rb +0 -52
  217. data/manual/table/basic_block.rb +0 -53
  218. data/manual/table/before_rendering_page.rb +0 -26
  219. data/manual/table/cell_border_lines.rb +0 -24
  220. data/manual/table/cell_borders_and_bg.rb +0 -31
  221. data/manual/table/cell_dimensions.rb +0 -30
  222. data/manual/table/cell_text.rb +0 -38
  223. data/manual/table/column_widths.rb +0 -30
  224. data/manual/table/content_and_subtables.rb +0 -39
  225. data/manual/table/creation.rb +0 -27
  226. data/manual/table/filtering.rb +0 -36
  227. data/manual/table/flow_and_header.rb +0 -17
  228. data/manual/table/image_cells.rb +0 -33
  229. data/manual/table/position.rb +0 -29
  230. data/manual/table/row_colors.rb +0 -20
  231. data/manual/table/span.rb +0 -30
  232. data/manual/table/style.rb +0 -22
  233. data/manual/table/table.rb +0 -52
  234. data/manual/table/width.rb +0 -27
  235. data/manual/text/alignment.rb +0 -44
  236. data/manual/text/color.rb +0 -24
  237. data/manual/text/column_box.rb +0 -32
  238. data/manual/text/fallback_fonts.rb +0 -37
  239. data/manual/text/font.rb +0 -41
  240. data/manual/text/font_size.rb +0 -45
  241. data/manual/text/font_style.rb +0 -23
  242. data/manual/text/formatted_callbacks.rb +0 -60
  243. data/manual/text/formatted_text.rb +0 -54
  244. data/manual/text/free_flowing_text.rb +0 -51
  245. data/manual/text/group.rb +0 -31
  246. data/manual/text/inline.rb +0 -43
  247. data/manual/text/kerning_and_character_spacing.rb +0 -39
  248. data/manual/text/leading.rb +0 -25
  249. data/manual/text/line_wrapping.rb +0 -41
  250. data/manual/text/paragraph_indentation.rb +0 -26
  251. data/manual/text/positioned_text.rb +0 -38
  252. data/manual/text/registering_families.rb +0 -48
  253. data/manual/text/rendering_and_color.rb +0 -37
  254. data/manual/text/right_to_left_text.rb +0 -43
  255. data/manual/text/rotation.rb +0 -43
  256. data/manual/text/single_usage.rb +0 -37
  257. data/manual/text/text.rb +0 -75
  258. data/manual/text/text_box_excess.rb +0 -32
  259. data/manual/text/text_box_extensions.rb +0 -45
  260. data/manual/text/text_box_overflow.rb +0 -44
  261. data/manual/text/utf8.rb +0 -28
  262. data/manual/text/win_ansi_charset.rb +0 -59
  263. data/spec/acceptance/png.rb +0 -23
  264. data/spec/column_box_spec.rb +0 -65
  265. data/spec/extensions/encoding_helpers.rb +0 -9
  266. data/spec/font_metric_cache_spec.rb +0 -52
  267. data/spec/image_handler_spec.rb +0 -54
  268. data/spec/soft_mask_spec.rb +0 -117
  269. data/spec/table/span_dummy_spec.rb +0 -17
@@ -10,24 +10,23 @@ require 'digest/sha1'
10
10
  module Prawn
11
11
  module Images
12
12
  class Image
13
- # @group Extension API
14
13
 
15
14
  def calc_image_dimensions(options)
16
15
  w = options[:width] || width
17
16
  h = options[:height] || height
18
17
 
19
18
  if options[:width] && !options[:height]
20
- wp = w / width.to_f
19
+ wp = w / width.to_f
21
20
  w = width * wp
22
21
  h = height * wp
23
- elsif options[:height] && !options[:width]
22
+ elsif options[:height] && !options[:width]
24
23
  hp = h / height.to_f
25
24
  w = width * hp
26
- h = height * hp
27
- elsif options[:scale]
25
+ h = height * hp
26
+ elsif options[:scale]
28
27
  w = width * options[:scale]
29
28
  h = height * options[:scale]
30
- elsif options[:fit]
29
+ elsif options[:fit]
31
30
  bw, bh = options[:fit]
32
31
  bp = bw / bh.to_f
33
32
  ip = width / height.to_f
@@ -44,6 +43,23 @@ module Prawn
44
43
 
45
44
  [w,h]
46
45
  end
46
+
47
+ def self.detect_image_format(content)
48
+ top = content[0,128]
49
+
50
+ # Unpack before comparing for JPG header, so as to avoid having to worry
51
+ # about the source string encoding. We just want a byte-by-byte compare.
52
+ if top[0, 3].unpack("C*") == [255, 216, 255]
53
+ return :jpg
54
+ elsif top[0, 8].unpack("C*") == [137, 80, 78, 71, 13, 10, 26, 10]
55
+ return :png
56
+ else
57
+ raise Errors::UnsupportedImageType, "image file is an unrecognised format"
58
+ end
59
+ end
60
+
61
+
47
62
  end
48
63
  end
49
64
  end
65
+
@@ -10,21 +10,15 @@ require 'stringio'
10
10
 
11
11
  module Prawn
12
12
  module Images
13
-
14
13
  # A convenience class that wraps the logic for extracting the parts
15
14
  # of a JPG image that we need to embed them in a PDF
16
15
  #
17
16
  class JPG < Image
18
- # @group Extension API
19
-
20
17
  attr_reader :width, :height, :bits, :channels
21
18
  attr_accessor :scaled_width, :scaled_height
22
-
23
- JPEG_SOF_BLOCKS = [0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF]
24
-
25
- def self.can_render?(image_blob)
26
- image_blob[0, 3].unpack("C*") == [255, 216, 255]
27
- end
19
+
20
+ JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
21
+ JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
28
22
 
29
23
  # Process a new JPG image
30
24
  #
@@ -32,21 +26,20 @@ module Prawn
32
26
  #
33
27
  def initialize(data)
34
28
  @data = data
35
- d = StringIO.new(@data)
36
- d.binmode
29
+ data = StringIO.new(data.dup)
37
30
 
38
- c_marker = 0xff # Section marker.
39
- d.seek(2) # Skip the first two bytes of JPEG identifier.
31
+ c_marker = "\xff" # Section marker.
32
+ data.read(2) # Skip the first two bytes of JPEG identifier.
40
33
  loop do
41
- marker, code, length = d.read(4).unpack('CCn')
34
+ marker, code, length = data.read(4).unpack('aan')
42
35
  raise "JPEG marker not found!" if marker != c_marker
43
36
 
44
37
  if JPEG_SOF_BLOCKS.include?(code)
45
- @bits, @height, @width, @channels = d.read(6).unpack("CnnC")
38
+ @bits, @height, @width, @channels = data.read(6).unpack("CnnC")
46
39
  break
47
40
  end
48
41
 
49
- d.seek(length - 2, IO::SEEK_CUR)
42
+ buffer = data.read(length - 2)
50
43
  end
51
44
  end
52
45
 
@@ -68,11 +61,13 @@ module Prawn
68
61
  obj = document.ref!(
69
62
  :Type => :XObject,
70
63
  :Subtype => :Image,
64
+ :Filter => :DCTDecode,
71
65
  :ColorSpace => color_space,
72
66
  :BitsPerComponent => bits,
73
67
  :Width => width,
74
- :Height => height
75
- )
68
+ :Height => height,
69
+ :Length => @data.size
70
+ )
76
71
 
77
72
  # add extra decode params for CMYK images. By swapping the
78
73
  # min and max values from the default, we invert the colours. See
@@ -81,8 +76,7 @@ module Prawn
81
76
  obj.data[:Decode] = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0 ]
82
77
  end
83
78
 
84
- obj.stream << @data
85
- obj.stream.filters << :DCTDecode
79
+ obj << @data
86
80
  obj
87
81
  end
88
82
 
@@ -17,18 +17,12 @@ module Prawn
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
-
22
20
  attr_reader :palette, :img_data, :transparency
23
21
  attr_reader :width, :height, :bits
24
22
  attr_reader :color_type, :compression_method, :filter_method
25
23
  attr_reader :interlace_method, :alpha_channel
26
24
  attr_accessor :scaled_width, :scaled_height
27
25
 
28
- def self.can_render?(image_blob)
29
- image_blob[0, 8].unpack("C*") == [137, 80, 78, 71, 13, 10, 26, 10]
30
- end
31
-
32
26
  # Process a new PNG image
33
27
  #
34
28
  # <tt>data</tt>:: A binary string of PNG data
@@ -94,8 +88,6 @@ module Prawn
94
88
 
95
89
  data.read(4) # Skip the CRC
96
90
  end
97
-
98
- @img_data = Zlib::Inflate.inflate(@img_data)
99
91
  end
100
92
 
101
93
  # number of color components to each pixel
@@ -109,17 +101,34 @@ module Prawn
109
101
  end
110
102
  end
111
103
 
104
+ # number of bits used per pixel
105
+ #
106
+ def pixel_bitlength
107
+ if alpha_channel?
108
+ self.bits * (self.colors + 1)
109
+ else
110
+ self.bits * self.colors
111
+ end
112
+ end
113
+
112
114
  # split the alpha channel data from the raw image data in images
113
115
  # where it's required.
114
116
  #
115
117
  def split_alpha_channel!
116
- split_image_data if alpha_channel?
118
+ unfilter_image_data if alpha_channel?
117
119
  end
118
120
 
119
121
  def alpha_channel?
120
122
  @color_type == 4 || @color_type == 6
121
123
  end
122
124
 
125
+ # Adobe Reader can't handle 16-bit png channels -- chop off the second
126
+ # byte (least significant)
127
+ #
128
+ def alpha_channel_bits
129
+ 8
130
+ end
131
+
123
132
  # Build a PDF object representing this image in +document+, and return
124
133
  # a Reference to it.
125
134
  #
@@ -159,31 +168,31 @@ module Prawn
159
168
  :Subtype => :Image,
160
169
  :Height => height,
161
170
  :Width => width,
162
- :BitsPerComponent => bits
171
+ :BitsPerComponent => bits,
172
+ :Length => img_data.size,
173
+ :Filter => :FlateDecode
163
174
  )
164
175
 
176
+ unless alpha_channel
177
+ obj.data[:DecodeParms] = {:Predictor => 15,
178
+ :Colors => colors,
179
+ :BitsPerComponent => bits,
180
+ :Columns => width}
181
+ end
182
+
165
183
  # append the actual image data to the object as a stream
166
184
  obj << img_data
167
-
168
- obj.stream.filters << {
169
- :FlateDecode => {
170
- :Predictor => 15,
171
- :Colors => colors,
172
- :BitsPerComponent => bits,
173
- :Columns => width
174
- }
175
- }
176
-
185
+
177
186
  # sort out the colours of the image
178
187
  if palette.empty?
179
188
  obj.data[:ColorSpace] = color
180
189
  else
181
190
  # embed the colour palette in the PDF as a object stream
182
- palette_obj = document.ref!({})
191
+ palette_obj = document.ref!(:Length => palette.size)
183
192
  palette_obj << palette
184
193
 
185
194
  # build the color space array for the image
186
- obj.data[:ColorSpace] = [:Indexed,
195
+ obj.data[:ColorSpace] = [:Indexed,
187
196
  :DeviceRGB,
188
197
  (palette.size / 3) -1,
189
198
  palette_obj]
@@ -224,20 +233,13 @@ module Prawn
224
233
  :Subtype => :Image,
225
234
  :Height => height,
226
235
  :Width => width,
227
- :BitsPerComponent => bits,
236
+ :BitsPerComponent => alpha_channel_bits,
237
+ :Length => alpha_channel.size,
238
+ :Filter => :FlateDecode,
228
239
  :ColorSpace => :DeviceGray,
229
240
  :Decode => [0, 1]
230
241
  )
231
- smask_obj.stream << alpha_channel
232
-
233
- smask_obj.stream.filters << {
234
- :FlateDecode => {
235
- :Predictor => 15,
236
- :Colors => 1,
237
- :BitsPerComponent => bits,
238
- :Columns => width
239
- }
240
- }
242
+ smask_obj << alpha_channel
241
243
  obj.data[:SMask] = smask_obj
242
244
  end
243
245
 
@@ -259,40 +261,95 @@ module Prawn
259
261
 
260
262
  private
261
263
 
262
- def split_image_data
263
- alpha_bytes = bits / 8
264
- color_bytes = colors * bits / 8
265
-
266
- scanline_length = (color_bytes + alpha_bytes) * self.width + 1
267
- scanlines = @img_data.bytesize / scanline_length
268
- pixels = self.width * self.height
269
-
270
- data = StringIO.new(@img_data)
271
- data.binmode
272
-
273
- color_data = [0x00].pack('C') * (pixels * color_bytes + scanlines)
274
- color = StringIO.new(color_data)
275
- color.binmode
276
-
277
- @alpha_channel = [0x00].pack('C') * (pixels * alpha_bytes + scanlines)
278
- alpha = StringIO.new(@alpha_channel)
279
- alpha.binmode
280
-
281
- scanlines.times do |line|
282
- data.seek(line * scanline_length)
264
+ def unfilter_image_data
265
+ data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
266
+ @img_data = ""
267
+ @alpha_channel = ""
268
+
269
+ pixel_bytes = pixel_bitlength / 8
270
+ scanline_length = pixel_bytes * self.width + 1
271
+ row = 0
272
+ pixels = []
273
+ paeth, pa, pb, pc = nil
274
+ until data.empty? do
275
+ row_data = data.slice! 0, scanline_length
276
+ filter = row_data.shift
277
+ case filter
278
+ when 0 # None
279
+ when 1 # Sub
280
+ row_data.each_with_index do |byte, index|
281
+ left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
282
+ row_data[index] = (byte + left) % 256
283
+ #p [byte, left, row_data[index]]
284
+ end
285
+ when 2 # Up
286
+ row_data.each_with_index do |byte, index|
287
+ col = index / pixel_bytes
288
+ upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
289
+ row_data[index] = (upper + byte) % 256
290
+ end
291
+ when 3 # Average
292
+ row_data.each_with_index do |byte, index|
293
+ col = index / pixel_bytes
294
+ upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
295
+ left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
283
296
 
284
- filter = data.getbyte
297
+ row_data[index] = (byte + ((left + upper)/2).floor) % 256
298
+ end
299
+ when 4 # Paeth
300
+ left = upper = upper_left = nil
301
+ row_data.each_with_index do |byte, index|
302
+ col = index / pixel_bytes
303
+
304
+ left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
305
+ if row.zero?
306
+ upper = upper_left = 0
307
+ else
308
+ upper = pixels[row-1][col][index % pixel_bytes]
309
+ upper_left = col.zero? ? 0 :
310
+ pixels[row-1][col-1][index % pixel_bytes]
311
+ end
312
+
313
+ p = left + upper - upper_left
314
+ pa = (p - left).abs
315
+ pb = (p - upper).abs
316
+ pc = (p - upper_left).abs
317
+
318
+ paeth = if pa <= pb && pa <= pc
319
+ left
320
+ elsif pb <= pc
321
+ upper
322
+ else
323
+ upper_left
324
+ end
325
+
326
+ row_data[index] = (byte + paeth) % 256
327
+ end
328
+ else
329
+ raise ArgumentError, "Invalid filter algorithm #{filter}"
330
+ end
285
331
 
286
- color.putc filter
287
- alpha.putc filter
332
+ s = []
333
+ row_data.each_slice pixel_bytes do |slice|
334
+ s << slice
335
+ end
336
+ pixels << s
337
+ row += 1
338
+ end
288
339
 
289
- self.width.times do
290
- color.write data.read(color_bytes)
291
- alpha.write data.read(alpha_bytes)
340
+ # convert the pixel data to seperate strings for colours and alpha
341
+ color_byte_size = self.colors * self.bits / 8
342
+ alpha_byte_size = alpha_channel_bits / 8
343
+ pixels.each do |this_row|
344
+ this_row.each do |pixel|
345
+ @img_data << pixel[0, color_byte_size].pack("C*")
346
+ @alpha_channel << pixel[color_byte_size, alpha_byte_size].pack("C*")
292
347
  end
293
348
  end
294
349
 
295
- @img_data = color_data
350
+ # compress the data
351
+ @img_data = Zlib::Deflate.deflate(@img_data)
352
+ @alpha_channel = Zlib::Deflate.deflate(@alpha_channel)
296
353
  end
297
354
  end
298
355
  end
data/lib/prawn/layout.rb CHANGED
@@ -1,15 +1,20 @@
1
- require_relative "table"
2
- require_relative "layout/grid"
1
+ require "prawn/table"
2
+ require 'prawn/layout/grid'
3
3
 
4
4
  module Prawn
5
- module Errors
5
+
6
+ module Errors
7
+
8
+ # This error is raised when table data is malformed
9
+ #
10
+ InvalidTableData = Class.new(StandardError)
6
11
 
7
- # This error is raised when table data is malformed
8
- #
9
- InvalidTableData = Class.new(StandardError)
12
+ # This error is raised when an empty or nil table is rendered
13
+ #
14
+ EmptyTable = Class.new(StandardError)
15
+ end
10
16
 
11
- # This error is raised when an empty or nil table is rendered
12
- #
13
- EmptyTable = Class.new(StandardError)
14
- end
17
+ module Layout
18
+
19
+ end
15
20
  end
@@ -1,22 +1,15 @@
1
1
  module Prawn
2
2
  class Document
3
- # @group Experimental API
4
-
5
- # Defines the grid system for a particular document. Takes the number of
6
- # rows and columns and the width to use for the gutter as the
3
+
4
+ # Defines the grid system for a particular document. Takes the number of
5
+ # rows and columns and the width to use for the gutter as the
7
6
  # keys :rows, :columns, :gutter, :row_gutter, :column_gutter
8
7
  #
9
- # Note that a completely new grid object is built each time define_grid()
10
- # is called. This means that all subsequent calls to grid() will use
11
- # the newly defined Grid object -- grids are not nestable like
12
- # bounding boxes are.
13
-
14
8
  def define_grid(options = {})
15
- @boxes = nil
16
9
  @grid = Grid.new(self, options)
17
10
  end
18
-
19
- # A method that can either be used to access a particular grid on the page
11
+
12
+ # A method that can either be used to access a particular grid on the page
20
13
  # or work with the grid system directly.
21
14
  #
22
15
  # @pdf.grid # Get the Grid directly
@@ -29,7 +22,7 @@ module Prawn
29
22
  @grid
30
23
  else
31
24
  g1, g2 = args
32
- if(g1.class == Array && g2.class == Array &&
25
+ if(g1.class == Array && g2.class == Array &&
33
26
  g1.length == 2 && g2.length == 2)
34
27
  multi_box(single_box(*g1), single_box(*g2))
35
28
  else
@@ -37,17 +30,15 @@ module Prawn
37
30
  end
38
31
  end
39
32
  end
40
-
41
- # A Grid represents the entire grid system of a Page and calculates
33
+
34
+ # A Grid represents the entire grid system of a Page and calculates
42
35
  # the column width and row height of the base box.
43
- #
44
- # @private
45
36
  class Grid
46
37
  attr_reader :pdf, :columns, :rows, :gutter, :row_gutter, :column_gutter
47
38
  def initialize(pdf, options = {}) # :nodoc:
48
39
  valid_options = [:columns, :rows, :gutter, :row_gutter, :column_gutter]
49
40
  Prawn.verify_options valid_options, options
50
-
41
+
51
42
  @pdf = pdf
52
43
  @columns = options[:columns]
53
44
  @rows = options[:rows]
@@ -58,7 +49,7 @@ module Prawn
58
49
  def column_width
59
50
  @column_width ||= subdivide(pdf.bounds.width, columns, column_gutter)
60
51
  end
61
-
52
+
62
53
  # Calculates the base height of boxes.
63
54
  def row_height
64
55
  @row_height ||= subdivide(pdf.bounds.height, rows, row_gutter)
@@ -74,11 +65,11 @@ module Prawn
74
65
  end
75
66
 
76
67
  private
77
-
68
+
78
69
  def subdivide(total, num, gutter)
79
70
  (total.to_f - (gutter * (num - 1).to_f)) / num.to_f
80
71
  end
81
-
72
+
82
73
  def set_gutter(options)
83
74
  if options.has_key?(:gutter)
84
75
  @gutter = options[:gutter].to_f
@@ -90,93 +81,92 @@ module Prawn
90
81
  end
91
82
  end
92
83
  end
93
-
94
- # A Box is a class that represents a bounded area of a page.
95
- # A Grid object has methods that allow easy access to the coordinates of
84
+
85
+ # A Box is a class that represents a bounded area of a page.
86
+ # A Grid object has methods that allow easy access to the coordinates of
96
87
  # its corners, which can be plugged into most existing prawnmethods.
97
88
  #
98
- # @private
99
- class GridBox
89
+ class Box #:nodoc:
100
90
  attr_reader :pdf
101
-
91
+
102
92
  def initialize(pdf, i, j)
103
93
  @pdf = pdf
104
94
  @i = i
105
95
  @j = j
106
96
  end
107
-
108
- # Mostly diagnostic method that outputs the name of a box as
97
+
98
+ # Mostly diagnostic method that outputs the name of a box as
109
99
  # col_num, row_num
110
100
  #
111
101
  def name
112
102
  "#{@i.to_s},#{@j.to_s}"
113
103
  end
114
-
104
+
115
105
  # :nodoc
116
106
  def total_height
117
107
  pdf.bounds.height.to_f
118
108
  end
119
-
109
+
120
110
  # Width of a box
121
111
  def width
122
112
  grid.column_width.to_f
123
113
  end
124
-
114
+
125
115
  # Height of a box
126
116
  def height
127
117
  grid.row_height.to_f
128
118
  end
129
-
119
+
130
120
  # Width of the gutter
131
121
  def gutter
132
122
  grid.gutter.to_f
133
123
  end
134
-
124
+
135
125
  # x-coordinate of left side
136
126
  def left
137
127
  @left ||= (width + grid.column_gutter) * @j.to_f
138
128
  end
139
-
140
- # x-coordinate of right side
129
+
130
+ # x-coordinate of right side
141
131
  def right
142
132
  @right ||= left + width
143
133
  end
144
-
134
+
145
135
  # y-coordinate of the top
146
136
  def top
147
137
  @top ||= total_height - ((height + grid.row_gutter) * @i.to_f)
148
138
  end
149
-
139
+
150
140
  # y-coordinate of the bottom
151
141
  def bottom
152
142
  @bottom ||= top - height
153
143
  end
154
-
144
+
155
145
  # x,y coordinates of top left corner
156
146
  def top_left
157
147
  [left, top]
158
148
  end
159
-
160
- # x,y coordinates of top right corner
149
+
150
+ # x,y coordinates of top right corner
161
151
  def top_right
162
152
  [right, top]
163
153
  end
164
-
154
+
165
155
  # x,y coordinates of bottom left corner
166
156
  def bottom_left
167
157
  [left, bottom]
168
158
  end
169
-
159
+
170
160
  # x,y coordinates of bottom right corner
171
161
  def bottom_right
172
162
  [right, bottom]
173
163
  end
174
-
164
+
175
165
  # Creates a standard bounding box based on the grid box.
176
166
  def bounding_box(&blk)
177
167
  pdf.bounding_box(top_left, :width => width, :height => height, &blk)
178
168
  end
179
-
169
+
180
170
  # Diagnostic method
181
171
  def show(grid_color = "CCCCCC")
182
172
  self.bounding_box do
@@ -185,30 +175,28 @@ module Prawn
185
175
  pdf.stroke_color = grid_color
186
176
  pdf.text self.name
187
177
  pdf.stroke_bounds
188
-
178
+
189
179
  pdf.stroke_color = original_stroke_color
190
180
  end
191
181
  end
192
-
182
+
193
183
  private
194
184
  def grid
195
185
  pdf.grid
196
186
  end
197
187
  end
198
-
188
+
199
189
  # A MultiBox is specified by 2 Boxes and spans the areas between.
200
- #
201
- # @private
202
- class MultiBox < GridBox #:nodoc:
190
+ class MultiBox < Box #:nodoc:
203
191
  def initialize(pdf, b1, b2)
204
192
  @pdf = pdf
205
193
  @bs = [b1, b2]
206
194
  end
207
-
195
+
208
196
  def name
209
197
  @bs.map {|b| b.name}.join(":")
210
198
  end
211
-
199
+
212
200
  def total_height
213
201
  @bs[0].total_height
214
202
  end
@@ -216,54 +204,54 @@ module Prawn
216
204
  def width
217
205
  right_box.right - left_box.left
218
206
  end
219
-
207
+
220
208
  def height
221
209
  top_box.top - bottom_box.bottom
222
210
  end
223
-
211
+
224
212
  def gutter
225
213
  @bs[0].gutter
226
214
  end
227
-
215
+
228
216
  def left
229
217
  left_box.left
230
218
  end
231
-
219
+
232
220
  def right
233
221
  right_box.right
234
222
  end
235
-
223
+
236
224
  def top
237
225
  top_box.top
238
226
  end
239
-
227
+
240
228
  def bottom
241
229
  bottom_box.bottom
242
230
  end
243
-
231
+
244
232
  private
245
233
  def left_box
246
234
  @left_box ||= @bs.min {|a,b| a.left <=> b.left}
247
235
  end
248
-
236
+
249
237
  def right_box
250
238
  @right_box ||= @bs.max {|a,b| a.right <=> b.right}
251
239
  end
252
-
240
+
253
241
  def top_box
254
242
  @top_box ||= @bs.max {|a,b| a.top <=> b.top}
255
243
  end
256
-
244
+
257
245
  def bottom_box
258
246
  @bottom_box ||= @bs.min {|a,b| a.bottom <=> b.bottom}
259
247
  end
260
248
  end
261
-
249
+
262
250
  private
263
251
  def single_box(i, j)
264
- GridBox.new(self, i, j)
252
+ Box.new(self, i, j)
265
253
  end
266
-
254
+
267
255
  def multi_box(b1, b2)
268
256
  MultiBox.new(self, b1, b2)
269
257
  end