prawn-git 2.0.1

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 (252) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +10 -0
  3. data/COPYING +2 -0
  4. data/GPLv2 +340 -0
  5. data/GPLv3 +674 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +56 -0
  8. data/Rakefile +55 -0
  9. data/data/fonts/Courier-Bold.afm +342 -0
  10. data/data/fonts/Courier-BoldOblique.afm +342 -0
  11. data/data/fonts/Courier-Oblique.afm +342 -0
  12. data/data/fonts/Courier.afm +342 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/images/16bit.alpha +0 -0
  25. data/data/images/16bit.color +0 -0
  26. data/data/images/16bit.png +0 -0
  27. data/data/images/arrow.png +0 -0
  28. data/data/images/arrow2.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.color +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/dice_interlaced.png +0 -0
  33. data/data/images/fractal.jpg +0 -0
  34. data/data/images/indexed_color.dat +0 -0
  35. data/data/images/indexed_color.png +0 -0
  36. data/data/images/letterhead.jpg +0 -0
  37. data/data/images/license.md +8 -0
  38. data/data/images/page_white_text.alpha +0 -0
  39. data/data/images/page_white_text.color +0 -0
  40. data/data/images/page_white_text.png +0 -0
  41. data/data/images/pal_bk.png +0 -0
  42. data/data/images/pigs.jpg +0 -0
  43. data/data/images/prawn.png +0 -0
  44. data/data/images/ruport.png +0 -0
  45. data/data/images/ruport_data.dat +0 -0
  46. data/data/images/ruport_transparent.png +0 -0
  47. data/data/images/ruport_type0.png +0 -0
  48. data/data/images/stef.jpg +0 -0
  49. data/data/images/tru256.bmp +0 -0
  50. data/data/images/web-links.dat +1 -0
  51. data/data/images/web-links.png +0 -0
  52. data/data/pdfs/complex_template.pdf +0 -0
  53. data/data/pdfs/contains_ttf_font.pdf +0 -0
  54. data/data/pdfs/encrypted.pdf +0 -0
  55. data/data/pdfs/form.pdf +820 -0
  56. data/data/pdfs/hexagon.pdf +61 -0
  57. data/data/pdfs/indirect_reference.pdf +86 -0
  58. data/data/pdfs/multipage_template.pdf +127 -0
  59. data/data/pdfs/nested_pages.pdf +118 -0
  60. data/data/pdfs/page_without_mediabox.pdf +193 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/lib/prawn.rb +89 -0
  66. data/lib/prawn/document.rb +706 -0
  67. data/lib/prawn/document/bounding_box.rb +539 -0
  68. data/lib/prawn/document/column_box.rb +144 -0
  69. data/lib/prawn/document/internals.rb +58 -0
  70. data/lib/prawn/document/span.rb +57 -0
  71. data/lib/prawn/encoding.rb +87 -0
  72. data/lib/prawn/errors.rb +80 -0
  73. data/lib/prawn/font.rb +413 -0
  74. data/lib/prawn/font/afm.rb +256 -0
  75. data/lib/prawn/font/dfont.rb +43 -0
  76. data/lib/prawn/font/ttf.rb +355 -0
  77. data/lib/prawn/font_metric_cache.rb +46 -0
  78. data/lib/prawn/graphics.rb +646 -0
  79. data/lib/prawn/graphics/cap_style.rb +47 -0
  80. data/lib/prawn/graphics/color.rb +232 -0
  81. data/lib/prawn/graphics/dash.rb +109 -0
  82. data/lib/prawn/graphics/join_style.rb +49 -0
  83. data/lib/prawn/graphics/patterns.rb +126 -0
  84. data/lib/prawn/graphics/transformation.rb +157 -0
  85. data/lib/prawn/graphics/transparency.rb +101 -0
  86. data/lib/prawn/grid.rb +279 -0
  87. data/lib/prawn/image_handler.rb +44 -0
  88. data/lib/prawn/images.rb +199 -0
  89. data/lib/prawn/images/image.rb +49 -0
  90. data/lib/prawn/images/jpg.rb +91 -0
  91. data/lib/prawn/images/png.rb +290 -0
  92. data/lib/prawn/measurement_extensions.rb +50 -0
  93. data/lib/prawn/measurements.rb +77 -0
  94. data/lib/prawn/outline.rb +289 -0
  95. data/lib/prawn/repeater.rb +124 -0
  96. data/lib/prawn/security.rb +288 -0
  97. data/lib/prawn/security/arcfour.rb +54 -0
  98. data/lib/prawn/soft_mask.rb +94 -0
  99. data/lib/prawn/stamp.rb +136 -0
  100. data/lib/prawn/text.rb +437 -0
  101. data/lib/prawn/text/box.rb +141 -0
  102. data/lib/prawn/text/formatted.rb +7 -0
  103. data/lib/prawn/text/formatted/arranger.rb +290 -0
  104. data/lib/prawn/text/formatted/box.rb +614 -0
  105. data/lib/prawn/text/formatted/fragment.rb +264 -0
  106. data/lib/prawn/text/formatted/line_wrap.rb +277 -0
  107. data/lib/prawn/text/formatted/parser.rb +224 -0
  108. data/lib/prawn/text/formatted/wrap.rb +160 -0
  109. data/lib/prawn/utilities.rb +46 -0
  110. data/lib/prawn/version.rb +5 -0
  111. data/lib/prawn/view.rb +91 -0
  112. data/manual/absolute_position.pdf +0 -0
  113. data/manual/basic_concepts/adding_pages.rb +27 -0
  114. data/manual/basic_concepts/basic_concepts.rb +36 -0
  115. data/manual/basic_concepts/creation.rb +39 -0
  116. data/manual/basic_concepts/cursor.rb +33 -0
  117. data/manual/basic_concepts/measurement.rb +25 -0
  118. data/manual/basic_concepts/origin.rb +38 -0
  119. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  120. data/manual/basic_concepts/view.rb +42 -0
  121. data/manual/bounding_box/bounding_box.rb +39 -0
  122. data/manual/bounding_box/bounds.rb +49 -0
  123. data/manual/bounding_box/canvas.rb +24 -0
  124. data/manual/bounding_box/creation.rb +23 -0
  125. data/manual/bounding_box/indentation.rb +46 -0
  126. data/manual/bounding_box/nesting.rb +45 -0
  127. data/manual/bounding_box/russian_boxes.rb +40 -0
  128. data/manual/bounding_box/stretchy.rb +31 -0
  129. data/manual/contents.rb +29 -0
  130. data/manual/cover.rb +39 -0
  131. data/manual/document_and_page_options/background.rb +27 -0
  132. data/manual/document_and_page_options/document_and_page_options.rb +32 -0
  133. data/manual/document_and_page_options/metadata.rb +23 -0
  134. data/manual/document_and_page_options/page_margins.rb +38 -0
  135. data/manual/document_and_page_options/page_size.rb +34 -0
  136. data/manual/document_and_page_options/print_scaling.rb +20 -0
  137. data/manual/example_helper.rb +7 -0
  138. data/manual/graphics/circle_and_ellipse.rb +22 -0
  139. data/manual/graphics/color.rb +24 -0
  140. data/manual/graphics/common_lines.rb +30 -0
  141. data/manual/graphics/fill_and_stroke.rb +42 -0
  142. data/manual/graphics/fill_rules.rb +37 -0
  143. data/manual/graphics/gradients.rb +37 -0
  144. data/manual/graphics/graphics.rb +58 -0
  145. data/manual/graphics/helper.rb +24 -0
  146. data/manual/graphics/line_width.rb +35 -0
  147. data/manual/graphics/lines_and_curves.rb +41 -0
  148. data/manual/graphics/polygon.rb +29 -0
  149. data/manual/graphics/rectangle.rb +21 -0
  150. data/manual/graphics/rotate.rb +28 -0
  151. data/manual/graphics/scale.rb +41 -0
  152. data/manual/graphics/soft_masks.rb +46 -0
  153. data/manual/graphics/stroke_cap.rb +31 -0
  154. data/manual/graphics/stroke_dash.rb +48 -0
  155. data/manual/graphics/stroke_join.rb +30 -0
  156. data/manual/graphics/translate.rb +29 -0
  157. data/manual/graphics/transparency.rb +35 -0
  158. data/manual/how_to_read_this_manual.rb +40 -0
  159. data/manual/images/absolute_position.rb +23 -0
  160. data/manual/images/fit.rb +21 -0
  161. data/manual/images/horizontal.rb +25 -0
  162. data/manual/images/images.rb +40 -0
  163. data/manual/images/plain_image.rb +18 -0
  164. data/manual/images/scale.rb +22 -0
  165. data/manual/images/vertical.rb +28 -0
  166. data/manual/images/width_and_height.rb +25 -0
  167. data/manual/layout/boxes.rb +27 -0
  168. data/manual/layout/content.rb +25 -0
  169. data/manual/layout/layout.rb +28 -0
  170. data/manual/layout/simple_grid.rb +23 -0
  171. data/manual/outline/add_subsection_to.rb +61 -0
  172. data/manual/outline/insert_section_after.rb +47 -0
  173. data/manual/outline/outline.rb +32 -0
  174. data/manual/outline/sections_and_pages.rb +67 -0
  175. data/manual/repeatable_content/alternate_page_numbering.rb +32 -0
  176. data/manual/repeatable_content/page_numbering.rb +54 -0
  177. data/manual/repeatable_content/repeatable_content.rb +32 -0
  178. data/manual/repeatable_content/repeater.rb +55 -0
  179. data/manual/repeatable_content/stamp.rb +41 -0
  180. data/manual/security/encryption.rb +31 -0
  181. data/manual/security/permissions.rb +38 -0
  182. data/manual/security/security.rb +28 -0
  183. data/manual/table.rb +16 -0
  184. data/manual/text/alignment.rb +44 -0
  185. data/manual/text/color.rb +24 -0
  186. data/manual/text/column_box.rb +32 -0
  187. data/manual/text/fallback_fonts.rb +37 -0
  188. data/manual/text/font.rb +41 -0
  189. data/manual/text/font_size.rb +45 -0
  190. data/manual/text/font_style.rb +23 -0
  191. data/manual/text/formatted_callbacks.rb +60 -0
  192. data/manual/text/formatted_text.rb +50 -0
  193. data/manual/text/free_flowing_text.rb +51 -0
  194. data/manual/text/inline.rb +41 -0
  195. data/manual/text/kerning_and_character_spacing.rb +39 -0
  196. data/manual/text/leading.rb +25 -0
  197. data/manual/text/line_wrapping.rb +41 -0
  198. data/manual/text/paragraph_indentation.rb +34 -0
  199. data/manual/text/positioned_text.rb +38 -0
  200. data/manual/text/registering_families.rb +48 -0
  201. data/manual/text/rendering_and_color.rb +37 -0
  202. data/manual/text/right_to_left_text.rb +47 -0
  203. data/manual/text/rotation.rb +43 -0
  204. data/manual/text/single_usage.rb +37 -0
  205. data/manual/text/text.rb +73 -0
  206. data/manual/text/text_box_excess.rb +32 -0
  207. data/manual/text/text_box_extensions.rb +45 -0
  208. data/manual/text/text_box_overflow.rb +48 -0
  209. data/manual/text/utf8.rb +28 -0
  210. data/manual/text/win_ansi_charset.rb +60 -0
  211. data/prawn.gemspec +45 -0
  212. data/spec/acceptance/png.rb +25 -0
  213. data/spec/annotations_spec.rb +74 -0
  214. data/spec/bounding_box_spec.rb +510 -0
  215. data/spec/column_box_spec.rb +65 -0
  216. data/spec/data/curves.pdf +66 -0
  217. data/spec/destinations_spec.rb +15 -0
  218. data/spec/document_spec.rb +748 -0
  219. data/spec/extensions/encoding_helpers.rb +11 -0
  220. data/spec/extensions/mocha.rb +46 -0
  221. data/spec/font_metric_cache_spec.rb +52 -0
  222. data/spec/font_spec.rb +474 -0
  223. data/spec/formatted_text_arranger_spec.rb +421 -0
  224. data/spec/formatted_text_box_spec.rb +705 -0
  225. data/spec/formatted_text_fragment_spec.rb +298 -0
  226. data/spec/graphics_spec.rb +683 -0
  227. data/spec/grid_spec.rb +96 -0
  228. data/spec/image_handler_spec.rb +54 -0
  229. data/spec/images_spec.rb +153 -0
  230. data/spec/inline_formatted_text_parser_spec.rb +564 -0
  231. data/spec/jpg_spec.rb +25 -0
  232. data/spec/line_wrap_spec.rb +367 -0
  233. data/spec/measurement_units_spec.rb +25 -0
  234. data/spec/outline_spec.rb +430 -0
  235. data/spec/png_spec.rb +245 -0
  236. data/spec/reference_spec.rb +25 -0
  237. data/spec/repeater_spec.rb +160 -0
  238. data/spec/security_spec.rb +158 -0
  239. data/spec/soft_mask_spec.rb +79 -0
  240. data/spec/span_spec.rb +44 -0
  241. data/spec/spec_helper.rb +54 -0
  242. data/spec/stamp_spec.rb +160 -0
  243. data/spec/stroke_styles_spec.rb +211 -0
  244. data/spec/text_at_spec.rb +143 -0
  245. data/spec/text_box_spec.rb +1043 -0
  246. data/spec/text_rendering_mode_spec.rb +45 -0
  247. data/spec/text_spacing_spec.rb +93 -0
  248. data/spec/text_spec.rb +557 -0
  249. data/spec/text_with_inline_formatting_spec.rb +35 -0
  250. data/spec/transparency_spec.rb +91 -0
  251. data/spec/view_spec.rb +43 -0
  252. metadata +509 -0
@@ -0,0 +1,245 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ # Spec'ing the PNG class. Not complete yet - still needs to check the
4
+ # contents of palette and transparency to ensure they're correct.
5
+ # Need to find files that have these sections first.
6
+ #
7
+ # see http://www.w3.org/TR/PNG/ for a detailed description of the PNG spec,
8
+ # particuarly Table 11.1 for the different color types
9
+
10
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
11
+
12
+ describe "When reading a greyscale PNG file (color type 0)" do
13
+
14
+ before(:each) do
15
+ @filename = "#{Prawn::DATADIR}/images/web-links.png"
16
+ @data_filename = "#{Prawn::DATADIR}/images/web-links.dat"
17
+ @img_data = File.binread(@filename)
18
+ end
19
+
20
+ it "should read the attributes from the header chunk correctly" do
21
+ png = Prawn::Images::PNG.new(@img_data)
22
+
23
+ png.width.should == 21
24
+ png.height.should == 14
25
+ png.bits.should == 8
26
+ png.color_type.should == 0
27
+ png.compression_method.should == 0
28
+ png.filter_method.should == 0
29
+ png.interlace_method.should == 0
30
+ end
31
+
32
+ it "should read the image data chunk correctly" do
33
+ png = Prawn::Images::PNG.new(@img_data)
34
+ data = Zlib::Inflate.inflate(File.binread(@data_filename))
35
+ png.img_data.should == data
36
+ end
37
+ end
38
+
39
+ describe "When reading a greyscale PNG file with transparency (color type 0)" do
40
+
41
+ before(:each) do
42
+ @filename = "#{Prawn::DATADIR}/images/ruport_type0.png"
43
+ @img_data = File.binread(@filename)
44
+ end
45
+
46
+ # In a greyscale type 0 PNG image, the tRNS chunk should contain a single value
47
+ # that indicates the color that should be interpreted as transparent.
48
+ #
49
+ # http://www.w3.org/TR/PNG/#11tRNS
50
+ it "should read the tRNS chunk correctly" do
51
+ png = Prawn::Images::PNG.new(@img_data)
52
+ png.transparency[:grayscale].should == 255
53
+ end
54
+ end
55
+
56
+ describe "When reading an RGB PNG file (color type 2)" do
57
+
58
+ before(:each) do
59
+ @filename = "#{Prawn::DATADIR}/images/ruport.png"
60
+ @data_filename = "#{Prawn::DATADIR}/images/ruport_data.dat"
61
+ @img_data = File.binread(@filename)
62
+ end
63
+
64
+ it "should read the attributes from the header chunk correctly" do
65
+ png = Prawn::Images::PNG.new(@img_data)
66
+
67
+ png.width.should == 258
68
+ png.height.should == 105
69
+ png.bits.should == 8
70
+ png.color_type.should == 2
71
+ png.compression_method.should == 0
72
+ png.filter_method.should == 0
73
+ png.interlace_method.should == 0
74
+ end
75
+
76
+ it "should read the image data chunk correctly" do
77
+ png = Prawn::Images::PNG.new(@img_data)
78
+ data = Zlib::Inflate.inflate(File.binread(@data_filename))
79
+ png.img_data.should == data
80
+ end
81
+ end
82
+
83
+ describe "When reading an RGB PNG file with transparency (color type 2)" do
84
+
85
+ before(:each) do
86
+ @filename = "#{Prawn::DATADIR}/images/arrow2.png"
87
+ @img_data = File.binread(@filename)
88
+ end
89
+
90
+ # In a RGB type 2 PNG image, the tRNS chunk should contain a single RGB value
91
+ # that indicates the color that should be interpreted as transparent. In this
92
+ # case it's green.
93
+ #
94
+ # http://www.w3.org/TR/PNG/#11tRNS
95
+ it "should read the tRNS chunk correctly" do
96
+ png = Prawn::Images::PNG.new(@img_data)
97
+ png.transparency[:rgb].should == [0, 255, 0]
98
+ end
99
+ end
100
+
101
+ describe "When reading an indexed color PNG file "+
102
+ "wiih transparency (color type 3)" do
103
+
104
+ it "raises a not supported error" do
105
+ bin = File.binread("#{Prawn::DATADIR}/images/pal_bk.png")
106
+ expect { Prawn::Images::PNG.new(bin)}.to(
107
+ raise_error(Prawn::Errors::UnsupportedImageType))
108
+ end
109
+ end
110
+
111
+ describe "When reading an indexed color PNG file (color type 3)" do
112
+
113
+ before(:each) do
114
+ @filename = "#{Prawn::DATADIR}/images/indexed_color.png"
115
+ @data_filename = "#{Prawn::DATADIR}/images/indexed_color.dat"
116
+ @img_data = File.binread(@filename)
117
+ end
118
+
119
+ it "should read the attributes from the header chunk correctly" do
120
+ png = Prawn::Images::PNG.new(@img_data)
121
+
122
+ png.width.should == 150
123
+ png.height.should == 200
124
+ png.bits.should == 8
125
+ png.color_type.should == 3
126
+ png.compression_method.should == 0
127
+ png.filter_method.should == 0
128
+ png.interlace_method.should == 0
129
+ end
130
+
131
+ it "should read the image data chunk correctly" do
132
+ png = Prawn::Images::PNG.new(@img_data)
133
+ data = Zlib::Inflate.inflate(File.binread(@data_filename))
134
+ png.img_data.should == data
135
+ end
136
+ end
137
+
138
+ describe "When reading a greyscale+alpha PNG file (color type 4)" do
139
+
140
+ before(:each) do
141
+ @filename = "#{Prawn::DATADIR}/images/page_white_text.png"
142
+ @color_data_filename = "#{Prawn::DATADIR}/images/page_white_text.color"
143
+ @alpha_data_filename = "#{Prawn::DATADIR}/images/page_white_text.alpha"
144
+ @img_data = File.binread(@filename)
145
+ end
146
+
147
+ it "should read the attributes from the header chunk correctly" do
148
+ png = Prawn::Images::PNG.new(@img_data)
149
+
150
+ png.width.should == 16
151
+ png.height.should == 16
152
+ png.bits.should == 8
153
+ png.color_type.should == 4
154
+ png.compression_method.should == 0
155
+ png.filter_method.should == 0
156
+ png.interlace_method.should == 0
157
+ end
158
+
159
+ it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
160
+ png = Prawn::Images::PNG.new(@img_data)
161
+ png.split_alpha_channel!
162
+ data = File.binread(@color_data_filename)
163
+ png.img_data.should == data
164
+ end
165
+
166
+ it "should correctly extract the alpha channel data from the image data chunk" do
167
+ png = Prawn::Images::PNG.new(@img_data)
168
+ png.split_alpha_channel!
169
+ data = File.binread(@alpha_data_filename)
170
+ png.alpha_channel.should == data
171
+ end
172
+ end
173
+
174
+ describe "When reading an RGB+alpha PNG file (color type 6)" do
175
+
176
+ before(:each) do
177
+ @filename = "#{Prawn::DATADIR}/images/dice.png"
178
+ @color_data_filename = "#{Prawn::DATADIR}/images/dice.color"
179
+ @alpha_data_filename = "#{Prawn::DATADIR}/images/dice.alpha"
180
+ @img_data = File.binread(@filename)
181
+ end
182
+
183
+ it "should read the attributes from the header chunk correctly" do
184
+ png = Prawn::Images::PNG.new(@img_data)
185
+
186
+ png.width.should == 320
187
+ png.height.should == 240
188
+ png.bits.should == 8
189
+ png.color_type.should == 6
190
+ png.compression_method.should == 0
191
+ png.filter_method.should == 0
192
+ png.interlace_method.should == 0
193
+ end
194
+
195
+ it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
196
+ png = Prawn::Images::PNG.new(@img_data)
197
+ png.split_alpha_channel!
198
+ data = File.binread(@color_data_filename)
199
+ png.img_data.should == data
200
+ end
201
+
202
+ it "should correctly extract the alpha channel data from the image data chunk" do
203
+ png = Prawn::Images::PNG.new(@img_data)
204
+ png.split_alpha_channel!
205
+ data = File.binread(@alpha_data_filename)
206
+ png.alpha_channel.should == data
207
+ end
208
+ end
209
+
210
+ describe "When reading a 16bit RGB+alpha PNG file (color type 6)" do
211
+
212
+ before(:each) do
213
+ @filename = "#{Prawn::DATADIR}/images/16bit.png"
214
+ @color_data_filename = "#{Prawn::DATADIR}/images/16bit.color"
215
+ # alpha channel truncated to 8-bit
216
+ @alpha_data_filename = "#{Prawn::DATADIR}/images/16bit.alpha"
217
+ @img_data = File.binread(@filename)
218
+ end
219
+
220
+ it "should read the attributes from the header chunk correctly" do
221
+ png = Prawn::Images::PNG.new(@img_data)
222
+
223
+ png.width.should == 32
224
+ png.height.should == 32
225
+ png.bits.should == 16
226
+ png.color_type.should == 6
227
+ png.compression_method.should == 0
228
+ png.filter_method.should == 0
229
+ png.interlace_method.should == 0
230
+ end
231
+
232
+ it "should correctly return the raw image data (with no alpha channel) from the image data chunk" do
233
+ png = Prawn::Images::PNG.new(@img_data)
234
+ png.split_alpha_channel!
235
+ data = File.binread(@color_data_filename)
236
+ png.img_data.should == data
237
+ end
238
+
239
+ it "should correctly extract the alpha channel data from the image data chunk" do
240
+ png = Prawn::Images::PNG.new(@img_data)
241
+ png.split_alpha_channel!
242
+ data = File.binread(@alpha_data_filename)
243
+ png.alpha_channel.should == data
244
+ end
245
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "A Reference object" do
6
+ describe "generated via Prawn::Document" do
7
+ it "should return a proper reference on ref!" do
8
+ pdf = Prawn::Document.new
9
+ pdf.ref!({}).is_a?(PDF::Core::Reference).should == true
10
+ end
11
+
12
+ it "should return an identifier on ref" do
13
+ pdf = Prawn::Document.new
14
+ r = pdf.ref({})
15
+ r.is_a?(Integer).should == true
16
+ end
17
+
18
+ it "should have :Length of stream if it has one when compression disabled" do
19
+ pdf = Prawn::Document.new :compress => false
20
+ ref = pdf.ref!({})
21
+ ref << 'Hello'
22
+ ref.stream.data[:Length].should == 5
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,160 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "Repeaters" do
6
+
7
+ it "creates a stamp and increments Prawn::Repeater.count on initialize" do
8
+ orig_count = Prawn::Repeater.count
9
+
10
+ doc = sample_document
11
+ doc.expects(:create_stamp).with("prawn_repeater(#{orig_count})")
12
+
13
+ r = repeater(doc, :all) { :do_nothing }
14
+
15
+ Prawn::Repeater.count.should == orig_count + 1
16
+ end
17
+
18
+ it "must provide an :all filter" do
19
+ doc = sample_document
20
+ r = repeater(doc, :all) { :do_nothing }
21
+
22
+ (1..doc.page_count).all? { |i| r.match?(i) }.should be_true
23
+ end
24
+
25
+ it "must provide an :odd filter" do
26
+ doc = sample_document
27
+ r = repeater(doc, :odd) { :do_nothing }
28
+
29
+ odd, even = (1..doc.page_count).partition { |e| e % 2 == 1 }
30
+
31
+ odd.all? { |i| r.match?(i) }.should be_true
32
+ even.any? { |i| r.match?(i) }.should be_false
33
+ end
34
+
35
+ it "must be able to filter by an array of page numbers" do
36
+ doc = sample_document
37
+ r = repeater(doc, [1,2,7]) { :do_nothing }
38
+
39
+ (1..10).select { |i| r.match?(i) }.should == [1,2,7]
40
+ end
41
+
42
+ it "must be able to filter by a range of page numbers" do
43
+ doc = sample_document
44
+ r = repeater(doc, 2..4) { :do_nothing }
45
+
46
+ (1..10).select { |i| r.match?(i) }.should == [2,3,4]
47
+ end
48
+
49
+ it "must be able to filter by an arbitrary proc" do
50
+ doc = sample_document
51
+ r = repeater(doc, lambda { |x| x == 1 or x % 3 == 0 })
52
+
53
+ (1..10).select { |i| r.match?(i) }.should == [1,3,6,9]
54
+ end
55
+
56
+ it "must try to run a stamp if the page number matches" do
57
+ doc = sample_document
58
+ doc.expects(:stamp)
59
+
60
+ repeater(doc, :odd).run(3)
61
+ end
62
+
63
+ it "must not try to run a stamp unless the page number matches" do
64
+ doc = sample_document
65
+
66
+ doc.expects(:stamp).never
67
+ repeater(doc, :odd).run(2)
68
+ end
69
+
70
+ it "must not try to run a stamp if dynamic is selected" do
71
+ doc = sample_document
72
+
73
+ doc.expects(:stamp).never
74
+ (1..10).each { |p| repeater(doc, :all, true){:do_nothing}.run(p) }
75
+ end
76
+
77
+ it "must try to run a block if the page number matches" do
78
+ doc = sample_document
79
+
80
+ doc.expects(:draw_text).twice
81
+ (1..10).each { |p| repeater(doc, [1,2], true){doc.draw_text "foo"}.run(p) }
82
+ end
83
+
84
+ it "must not try to run a block unless the page number matches" do
85
+ doc = sample_document
86
+
87
+ doc.expects(:draw_text).never
88
+ repeater(doc, :odd, true){doc.draw_text "foo"}.run(2)
89
+ end
90
+
91
+ it "must treat any block as a closure" do
92
+ doc = sample_document
93
+
94
+ @page = "Page" # ensure access to ivars
95
+ doc.repeat(:all, :dynamic => true) do
96
+ doc.draw_text "#@page #{doc.page_number}", :at => [500, 0]
97
+ end
98
+
99
+ text = PDF::Inspector::Text.analyze(doc.render)
100
+ text.strings.should == (1..10).to_a.map{|p| "Page #{p}"}
101
+ end
102
+
103
+ it "must treat any block as a closure (Document.new instance_eval form)" do
104
+ doc = Prawn::Document.new(:skip_page_creation => true) do
105
+ 10.times { start_new_page }
106
+
107
+ @page = "Page"
108
+ repeat(:all, :dynamic => true) do
109
+ # ensure self is accessible here
110
+ draw_text "#@page #{page_number}", :at => [500, 0]
111
+ end
112
+ end
113
+
114
+ text = PDF::Inspector::Text.analyze(doc.render)
115
+ text.strings.should == (1..10).to_a.map{|p| "Page #{p}"}
116
+ end
117
+
118
+ def sample_document
119
+ doc = Prawn::Document.new(:skip_page_creation => true)
120
+ 10.times { |e| doc.start_new_page }
121
+ doc
122
+ end
123
+
124
+ def repeater(*args, &b)
125
+ Prawn::Repeater.new(*args,&b)
126
+ end
127
+
128
+ context "graphic state" do
129
+
130
+ it "should not alter the graphic state stack color space" do
131
+ create_pdf
132
+ starting_color_space = @pdf.state.page.graphic_state.color_space.dup
133
+ @pdf.repeat :all do
134
+ @pdf.text "Testing", :size => 24, :style => :bold
135
+ end
136
+ @pdf.state.page.graphic_state.color_space.should == starting_color_space
137
+ end
138
+
139
+ context "dynamic repeaters" do
140
+
141
+ it "should preserve the graphic state at creation time" do
142
+ create_pdf
143
+ @pdf.repeat :all, :dynamic => true do
144
+ @pdf.text "fill_color: #{@pdf.graphic_state.fill_color}"
145
+ @pdf.text "cap_style: #{@pdf.graphic_state.cap_style}"
146
+ end
147
+ @pdf.fill_color "666666"
148
+ @pdf.cap_style :round
149
+ text = PDF::Inspector::Text.analyze(@pdf.render)
150
+ text.strings.include?("fill_color: 666666").should == false
151
+ text.strings.include?("fill_color: 000000").should == true
152
+ text.strings.include?("cap_style: round").should == false
153
+ text.strings.include?("cap_style: butt").should == true
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ end
@@ -0,0 +1,158 @@
1
+ # encoding: utf-8
2
+ require "tempfile"
3
+
4
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
5
+
6
+ describe "Document encryption" do
7
+
8
+ describe "Password padding" do
9
+
10
+ include Prawn::Document::Security
11
+
12
+ it "should truncate long passwords" do
13
+ pw = "Long long string" * 30
14
+ padded = pad_password(pw)
15
+ padded.length.should == 32
16
+ padded.should == pw[0, 32]
17
+ end
18
+
19
+ it "should pad short passwords" do
20
+ pw = "abcd"
21
+ padded = pad_password(pw)
22
+ padded.length.should == 32
23
+ padded.should == pw + Prawn::Document::Security::PasswordPadding[0, 28]
24
+ end
25
+
26
+ it "should fully pad null passwords" do
27
+ pw = ""
28
+ padded = pad_password(pw)
29
+ padded.length.should == 32
30
+ padded.should == Prawn::Document::Security::PasswordPadding
31
+ end
32
+
33
+ end
34
+
35
+ describe "Setting permissions" do
36
+
37
+ def doc_with_permissions(permissions)
38
+ pdf = Prawn::Document.new
39
+
40
+ class << pdf
41
+ # Make things easier to test
42
+ public :permissions_value
43
+ end
44
+
45
+ pdf.encrypt_document(:permissions => permissions)
46
+ pdf
47
+ end
48
+
49
+ it "should default to full permissions" do
50
+ doc_with_permissions({}).permissions_value.should == 0xFFFFFFFF
51
+ doc_with_permissions(:print_document => true,
52
+ :modify_contents => true,
53
+ :copy_contents => true,
54
+ :modify_annotations => true).permissions_value.
55
+ should == 0xFFFFFFFF
56
+ end
57
+
58
+ it "should clear the appropriate bits for each permission flag" do
59
+ doc_with_permissions(:print_document => false).permissions_value.
60
+ should == 0b1111_1111_1111_1111_1111_1111_1111_1011
61
+ doc_with_permissions(:modify_contents => false).permissions_value.
62
+ should == 0b1111_1111_1111_1111_1111_1111_1111_0111
63
+ doc_with_permissions(:copy_contents => false).permissions_value.
64
+ should == 0b1111_1111_1111_1111_1111_1111_1110_1111
65
+ doc_with_permissions(:modify_annotations => false).permissions_value.
66
+ should == 0b1111_1111_1111_1111_1111_1111_1101_1111
67
+ end
68
+
69
+ it "should raise_error ArgumentError if invalid option is provided" do
70
+ lambda {
71
+ doc_with_permissions(:modify_document => false)
72
+ }.should raise_error(ArgumentError)
73
+ end
74
+
75
+ end
76
+
77
+ describe "Encryption keys" do
78
+ # Since PDF::Reader doesn't read encrypted PDF files, we just take the
79
+ # roundabout method of verifying each step of the encryption. This works
80
+ # fine because the encryption method is deterministic.
81
+
82
+ before(:each) do
83
+ @pdf = Prawn::Document.new
84
+ class << @pdf
85
+ public :owner_password_hash, :user_password_hash, :user_encryption_key
86
+ end
87
+ @pdf.encrypt_document :user_password => 'foo', :owner_password => 'bar',
88
+ :permissions => { :print_document => false }
89
+ end
90
+
91
+ it "should calculate the correct owner hash" do
92
+ @pdf.owner_password_hash.unpack("H*").first.should match(/^61CA855012/i)
93
+ end
94
+
95
+ it "should calculate the correct user hash" do
96
+ @pdf.user_password_hash.unpack("H*").first.should =~ /^6BC8C51031/i
97
+ end
98
+
99
+ it "should calculate the correct user_encryption_key" do
100
+ @pdf.user_encryption_key.unpack("H*").first.upcase.should == "B100AB6429"
101
+ end
102
+
103
+
104
+ end
105
+
106
+ describe "EncryptedPdfObject" do
107
+
108
+ it "should delegate to PdfObject for simple types" do
109
+ PDF::Core::EncryptedPdfObject(true, nil, nil, nil).should == "true"
110
+ PDF::Core::EncryptedPdfObject(42, nil, nil, nil).should == "42"
111
+ end
112
+
113
+ it "should encrypt strings properly" do
114
+ PDF::Core::EncryptedPdfObject("foo", "12345", 123, 0).should == "<4ad6e3>"
115
+ end
116
+
117
+ it "should encrypt literal strings properly" do
118
+ PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("foo"), "12345", 123, 0).should == bin_string("(J\xD6\xE3)")
119
+ PDF::Core::EncryptedPdfObject(PDF::Core::LiteralString.new("lhfbqg3do5u0satu3fjf"), nil, 123, 0).should == bin_string("(\xF1\x8B\\(\b\xBB\xE18S\x130~4*#\\(%\x87\xE7\x8E\\\n)")
120
+ end
121
+
122
+ it "should encrypt time properly" do
123
+ PDF::Core::EncryptedPdfObject(Time.utc(2050, 04, 26, 10, 17, 10), "12345", 123, 0).should == bin_string("(h\x83\xBE\xDC\xEC\x99\x0F\xD7\\)%\x13\xD4$\xB8\xF0\x16\xB8\x80\xC5\xE91+\xCF)")
124
+ end
125
+
126
+ it "should properly handle compound types" do
127
+ PDF::Core::EncryptedPdfObject({:Bar => "foo"}, "12345", 123, 0).should ==
128
+ "<< /Bar <4ad6e3>\n>>"
129
+ PDF::Core::EncryptedPdfObject(["foo", "bar"], "12345", 123, 0).should ==
130
+ "[<4ad6e3> <4ed8fe>]"
131
+ end
132
+
133
+ end
134
+
135
+ describe "Reference#encrypted_object" do
136
+ it "should encrypt references properly" do
137
+ ref = PDF::Core::Reference(1,["foo"])
138
+ ref.encrypted_object(nil).should == "1 0 obj\n[<4fca3f>]\nendobj\n"
139
+ end
140
+
141
+ it "should encrypt references with streams properly" do
142
+ ref = PDF::Core::Reference(1, {})
143
+ ref << 'foo'
144
+ result = bin_string("1 0 obj\n<< /Length 3\n>>\nstream\nO\xCA?\nendstream\nendobj\n")
145
+ ref.encrypted_object(nil).should == result
146
+ end
147
+ end
148
+
149
+ describe "String#encrypted_object" do
150
+ it "should encrypt stream properly" do
151
+ stream = PDF::Core::Stream.new
152
+ stream << "foo"
153
+ result = bin_string("stream\nO\xCA?\nendstream\n")
154
+ stream.encrypted_object(nil, 1, 0).should == result
155
+ end
156
+ end
157
+
158
+ end