prawn 0.15.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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