fullcirclegroup-fullcirclegroup-prawn 0.2.99.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +47 -0
  4. data/Rakefile +76 -0
  5. data/data/fonts/Activa.ttf +0 -0
  6. data/data/fonts/Chalkboard.ttf +0 -0
  7. data/data/fonts/Courier-Bold.afm +342 -0
  8. data/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/data/fonts/Courier-Oblique.afm +342 -0
  10. data/data/fonts/Courier.afm +342 -0
  11. data/data/fonts/DejaVuSans.ttf +0 -0
  12. data/data/fonts/Dustismo_Roman.ttf +0 -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/fonts/comicsans.ttf +0 -0
  25. data/data/fonts/gkai00mp.ttf +0 -0
  26. data/data/images/arrow.png +0 -0
  27. data/data/images/arrow2.png +0 -0
  28. data/data/images/barcode_issue.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.dat +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/page_white_text.alpha +0 -0
  33. data/data/images/page_white_text.dat +0 -0
  34. data/data/images/page_white_text.png +0 -0
  35. data/data/images/pigs.jpg +0 -0
  36. data/data/images/rails.dat +0 -0
  37. data/data/images/rails.png +0 -0
  38. data/data/images/ruport.png +0 -0
  39. data/data/images/ruport_data.dat +0 -0
  40. data/data/images/ruport_transparent.png +0 -0
  41. data/data/images/ruport_type0.png +0 -0
  42. data/data/images/stef.jpg +0 -0
  43. data/data/images/web-links.dat +1 -0
  44. data/data/images/web-links.png +0 -0
  45. data/data/shift_jis_text.txt +1 -0
  46. data/examples/addressbook.csv +6 -0
  47. data/examples/alignment.rb +16 -0
  48. data/examples/bounding_boxes.rb +30 -0
  49. data/examples/canvas.rb +12 -0
  50. data/examples/cell.rb +38 -0
  51. data/examples/chinese_text_wrapping.rb +17 -0
  52. data/examples/currency.csv +1834 -0
  53. data/examples/curves.rb +10 -0
  54. data/examples/family_based_styling.rb +21 -0
  55. data/examples/fancy_table.rb +61 -0
  56. data/examples/flowing_text_with_header_and_footer.rb +72 -0
  57. data/examples/font_size.rb +27 -0
  58. data/examples/hexagon.rb +14 -0
  59. data/examples/image.rb +23 -0
  60. data/examples/image2.rb +13 -0
  61. data/examples/image_flow.rb +34 -0
  62. data/examples/kerning.rb +27 -0
  63. data/examples/lazy_bounding_boxes.rb +19 -0
  64. data/examples/line.rb +31 -0
  65. data/examples/multi_page_layout.rb +14 -0
  66. data/examples/page_geometry.rb +28 -0
  67. data/examples/png_types.rb +23 -0
  68. data/examples/polygons.rb +16 -0
  69. data/examples/position_by_baseline.rb +26 -0
  70. data/examples/ruport_formatter.rb +50 -0
  71. data/examples/ruport_helpers.rb +18 -0
  72. data/examples/russian_boxes.rb +34 -0
  73. data/examples/simple_text.rb +15 -0
  74. data/examples/simple_text_ttf.rb +16 -0
  75. data/examples/sjis.rb +21 -0
  76. data/examples/span.rb +27 -0
  77. data/examples/table.rb +47 -0
  78. data/examples/table_header_color.rb +16 -0
  79. data/examples/text_flow.rb +65 -0
  80. data/examples/top_and_bottom_cells.rb +40 -0
  81. data/examples/utf8.rb +12 -0
  82. data/lib/prawn.rb +67 -0
  83. data/lib/prawn/compatibility.rb +46 -0
  84. data/lib/prawn/document.rb +309 -0
  85. data/lib/prawn/document/bounding_box.rb +362 -0
  86. data/lib/prawn/document/internals.rb +113 -0
  87. data/lib/prawn/document/page_geometry.rb +79 -0
  88. data/lib/prawn/document/span.rb +47 -0
  89. data/lib/prawn/document/table.rb +350 -0
  90. data/lib/prawn/document/text.rb +196 -0
  91. data/lib/prawn/errors.rb +48 -0
  92. data/lib/prawn/font.rb +356 -0
  93. data/lib/prawn/font/cmap.rb +59 -0
  94. data/lib/prawn/font/metrics.rb +378 -0
  95. data/lib/prawn/font/wrapping.rb +47 -0
  96. data/lib/prawn/graphics.rb +252 -0
  97. data/lib/prawn/graphics/cell.rb +264 -0
  98. data/lib/prawn/graphics/color.rb +132 -0
  99. data/lib/prawn/images.rb +336 -0
  100. data/lib/prawn/images/jpg.rb +45 -0
  101. data/lib/prawn/images/png.rb +199 -0
  102. data/lib/prawn/pdf_object.rb +73 -0
  103. data/lib/prawn/reference.rb +56 -0
  104. data/spec/bounding_box_spec.rb +141 -0
  105. data/spec/document_spec.rb +181 -0
  106. data/spec/font_spec.rb +141 -0
  107. data/spec/graphics_spec.rb +209 -0
  108. data/spec/images_spec.rb +68 -0
  109. data/spec/jpg_spec.rb +25 -0
  110. data/spec/metrics_spec.rb +62 -0
  111. data/spec/pdf_object_spec.rb +112 -0
  112. data/spec/png_spec.rb +196 -0
  113. data/spec/reference_spec.rb +42 -0
  114. data/spec/spec_helper.rb +23 -0
  115. data/spec/table_spec.rb +179 -0
  116. data/spec/text_spec.rb +135 -0
  117. metadata +181 -0
@@ -0,0 +1,132 @@
1
+ module Prawn
2
+ module Graphics
3
+ module Color
4
+
5
+ # Sets the fill color.
6
+ #
7
+ # If a single argument is provided, it should be a 6 digit HTML color
8
+ # code.
9
+ #
10
+ # pdf.fill_color "f0ffc1"
11
+ #
12
+ # If 4 arguments are provided, the color is assumed to be a CMYK value
13
+ # Values range from 0 - 100.
14
+ #
15
+ # pdf.fill_color 0, 99, 95, 0
16
+ #
17
+ def fill_color(*color)
18
+ return @fill_color if color.empty?
19
+ @fill_color = process_color(*color)
20
+ set_fill_color
21
+ end
22
+
23
+ alias_method :fill_color=, :fill_color
24
+
25
+ # Sets the line stroking color. 6 digit HTML color codes are used.
26
+ #
27
+ # If a single argument is provided, it should be a 6 digit HTML color
28
+ # code.
29
+ #
30
+ # pdf.fill_color "f0ffc1"
31
+ #
32
+ # If 4 arguments are provided, the color is assumed to be a CMYK value
33
+ # Values range from 0 - 100.
34
+ #
35
+ # pdf.fill_color 0, 99, 95, 0
36
+ #
37
+ def stroke_color(*color)
38
+ return @stroke_color if color.empty?
39
+ @stroke_color = process_color(*color)
40
+ set_stroke_color
41
+ end
42
+
43
+ alias_method :stroke_color=, :stroke_color
44
+
45
+ # Provides the following shortcuts:
46
+ #
47
+ # stroke_some_method(*args) #=> some_method(*args); stroke
48
+ # fill_some_method(*args) #=> some_method(*args); fill
49
+ #
50
+ def method_missing(id,*args,&block)
51
+ case(id.to_s)
52
+ when /^fill_and_stroke_(.*)/
53
+ send($1,*args,&block); fill_and_stroke
54
+ when /^stroke_(.*)/
55
+ send($1,*args,&block); stroke
56
+ when /^fill_(.*)/
57
+ send($1,*args,&block); fill
58
+ else
59
+ super
60
+ end
61
+ end
62
+
63
+ module_function
64
+
65
+ # Converts RGB value array to hex string suitable for use with fill_color
66
+ # and stroke_color
67
+ #
68
+ # >> Prawn::Graphics::Color.rgb2hex([255,120,8])
69
+ # => "ff7808"
70
+ #
71
+ def rgb2hex(rgb)
72
+ rgb.map { |e| "%02x" % e }.join
73
+ end
74
+
75
+ # Converts hex string into RGB value array:
76
+ #
77
+ # >> Prawn::Graphics::Color.hex2rgb("ff7808")
78
+ # => [255, 120, 8]
79
+ #
80
+ def hex2rgb(hex)
81
+ r,g,b = hex[0..1], hex[2..3], hex[4..5]
82
+ [r,g,b].map { |e| e.to_i(16) }
83
+ end
84
+
85
+ private
86
+
87
+ def process_color(*color)
88
+ case(color.size)
89
+ when 1
90
+ color[0]
91
+ when 4
92
+ color
93
+ else
94
+ raise ArgumentError, 'wrong number of arguments supplied'
95
+ end
96
+ end
97
+
98
+ def set_fill_color
99
+ case @fill_color
100
+ when String
101
+ r,g,b = hex2rgb(@fill_color)
102
+ add_content "%.3f %.3f %.3f rg" %
103
+ [r / 255.0, g / 255.0, b / 255.0]
104
+ when Array
105
+ c,m,y,k = *@fill_color
106
+ add_content "%.3f %.3f %.3f %.3f k" %
107
+ [c / 100.0, m / 100.0, y / 100.0, k / 100.0]
108
+ end
109
+ end
110
+
111
+ def set_stroke_color
112
+ case @stroke_color
113
+ when String
114
+ r,g,b = hex2rgb(@stroke_color)
115
+ add_content "%.3f %.3f %.3f RG" %
116
+ [r / 255.0, g / 255.0, b / 255.0]
117
+ when Array
118
+ c,m,y,k = *@stroke_color
119
+ add_content "%.3f %.3f %.3f %.3f K" %
120
+ [c / 100.0, m / 100.0, y / 100.0, k / 100.0]
121
+ end
122
+ end
123
+
124
+ def update_colors
125
+ @fill_color ||= "000000"
126
+ @stroke_color ||= "000000"
127
+ set_fill_color
128
+ set_stroke_color
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,336 @@
1
+ # encoding: ASCII-8BIT
2
+ # images.rb : Implements PDF image embedding
3
+ #
4
+ # Copyright April 2008, James Healy, Gregory Brown. All Rights Reserved.
5
+ #
6
+ # This is free software. Please see the LICENSE and COPYING files for details.
7
+
8
+ require 'digest/sha1'
9
+
10
+ module Prawn
11
+
12
+ module Images
13
+
14
+ # add the image at filename to the current page. Currently only
15
+ # JPG and PNG files are supported.
16
+ #
17
+ # Arguments:
18
+ # <tt>file</tt>:: path to file or an object that responds to #read
19
+ #
20
+ # Options:
21
+ # <tt>:at</tt>:: an array [x,y] with the location of the top left corner of the image.
22
+ # <tt>:position</tt>:: One of (:left, :center, :right) or an x-offset
23
+ # <tt>:vposition</tt>:: One of (:top, :center, :center) or an y-offset
24
+ # <tt>:height</tt>:: the height of the image [actual height of the image]
25
+ # <tt>:width</tt>:: the width of the image [actual width of the image]
26
+ # <tt>:scale</tt>:: scale the dimensions of the image proportionally
27
+ # <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit inside [width,height]
28
+ #
29
+ # Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do
30
+ # pigs = "#{Prawn::BASEDIR}/data/images/pigs.jpg"
31
+ # image pigs, :at => [50,450], :width => 450
32
+ #
33
+ # dice = "#{Prawn::BASEDIR}/data/images/dice.png"
34
+ # image dice, :at => [50, 450], :scale => 0.75
35
+ # end
36
+ #
37
+ # If only one of :width / :height are provided, the image will be scaled
38
+ # proportionally. When both are provided, the image will be stretched to
39
+ # fit the dimensions without maintaining the aspect ratio.
40
+ #
41
+ # If :at is provided, the image will be place in the current page but
42
+ # the text position will not be changed.
43
+ #
44
+ # If instead of an explicit filename, an object with a read method is
45
+ # passed as +file+, you can embed images from IO objects and things
46
+ # that act like them (including Tempfiles and open-uri objects).
47
+ #
48
+ # require "open-uri"
49
+ #
50
+ # Prawn::Document.generate("remote_images.pdf") do
51
+ # image open("http://prawn.majesticseacreature.com/media/prawn_logo.png")
52
+ # end
53
+ #
54
+ # This method returns an image info object which can be used to check the
55
+ # dimensions of an image object if needed.
56
+ # (See also: Prawn::Images::PNG , Prawn::Images::JPG)
57
+ #
58
+ def image(file, options={})
59
+ Prawn.verify_options [:at, :position, :vposition, :height, :width, :scale, :fit], options
60
+
61
+ if file.respond_to?(:read)
62
+ image_content = file.read
63
+ else
64
+ raise ArgumentError, "#{file} not found" unless File.file?(file)
65
+ image_content = File.read_binary(file)
66
+ end
67
+
68
+ image_sha1 = Digest::SHA1.hexdigest(image_content)
69
+
70
+ # register the fact that the current page uses images
71
+ proc_set :ImageC
72
+
73
+ # if this image has already been embedded, just reuse it
74
+ image_obj = image_registry[image_sha1]
75
+
76
+ if image_registry[image_sha1]
77
+ info = image_registry[image_sha1][:info]
78
+ image_obj = image_registry[image_sha1][:obj]
79
+ else
80
+ # build the image object and embed the raw data
81
+ image_obj = case detect_image_format(image_content)
82
+ when :jpg then
83
+ info = Prawn::Images::JPG.new(image_content)
84
+ build_jpg_object(image_content, info)
85
+ when :png then
86
+ info = Prawn::Images::PNG.new(image_content)
87
+ build_png_object(image_content, info)
88
+ end
89
+ image_registry[image_sha1] = {:obj => image_obj, :info => info}
90
+ end
91
+
92
+ # find where the image will be placed and how big it will be
93
+ w,h = calc_image_dimensions(info, options)
94
+
95
+ if options[:at]
96
+ x,y = translate(options[:at])
97
+ else
98
+ x,y = image_position(w,h,options)
99
+ move_text_position h
100
+ end
101
+
102
+ # add a reference to the image object to the current page
103
+ # resource list and give it a label
104
+ label = "I#{next_image_id}"
105
+ page_xobjects.merge!( label => image_obj )
106
+
107
+ # add the image to the current page
108
+ instruct = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
109
+ add_content instruct % [ w, h, x, y - h, label ]
110
+
111
+ return info
112
+ end
113
+
114
+ private
115
+
116
+ def image_position(w,h,options)
117
+ options[:position] ||= :left
118
+
119
+ x = case options[:position]
120
+ when :left
121
+ bounds.absolute_left
122
+ when :center
123
+ bounds.absolute_left + (bounds.width - w) / 2.0
124
+ when :right
125
+ bounds.absolute_right - w
126
+ when Numeric
127
+ options[:position] + bounds.absolute_left
128
+ end
129
+
130
+ y = case options[:vposition]
131
+ when :top
132
+ bounds.absolute_top
133
+ when :center
134
+ bounds.absolute_top - (bounds.height - h) / 2.0
135
+ when :bottom
136
+ bounds.absolute_bottom + h
137
+ when Numeric
138
+ bounds.absolute_top - options[:vposition]
139
+ else
140
+ self.y
141
+ end
142
+ return [x,y]
143
+ end
144
+
145
+ def build_jpg_object(data, jpg)
146
+ color_space = case jpg.channels
147
+ when 1
148
+ :DeviceGray
149
+ when 3
150
+ :DeviceRGB
151
+ when 4
152
+ :DeviceCMYK
153
+ else
154
+ raise ArgumentError, 'JPG uses an unsupported number of channels'
155
+ end
156
+ obj = ref(:Type => :XObject,
157
+ :Subtype => :Image,
158
+ :Filter => :DCTDecode,
159
+ :ColorSpace => color_space,
160
+ :BitsPerComponent => jpg.bits,
161
+ :Width => jpg.width,
162
+ :Height => jpg.height,
163
+ :Length => data.size )
164
+
165
+ # add extra decode params for CMYK images. By swapping the
166
+ # min and max values from the default, we invert the colours. See
167
+ # section 4.8.4 of the spec.
168
+ if color_space == :DeviceCMYK
169
+ obj.data[:Decode] = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0 ]
170
+ end
171
+
172
+ obj << data
173
+ return obj
174
+ end
175
+
176
+ def build_png_object(data, png)
177
+
178
+ if png.compression_method != 0
179
+ raise ArgumentError, 'PNG uses an unsupported compression method'
180
+ end
181
+
182
+ if png.filter_method != 0
183
+ raise ArgumentError, 'PNG uses an unsupported filter method'
184
+ end
185
+
186
+ if png.interlace_method != 0
187
+ raise ArgumentError, 'PNG uses unsupported interlace method'
188
+ end
189
+
190
+ if png.bits > 8
191
+ raise ArgumentError, 'PNG uses more than 8 bits'
192
+ end
193
+
194
+ case png.pixel_bytes
195
+ when 1
196
+ color = :DeviceGray
197
+ when 3
198
+ color = :DeviceRGB
199
+ end
200
+
201
+ # build the image dict
202
+ obj = ref(:Type => :XObject,
203
+ :Subtype => :Image,
204
+ :Height => png.height,
205
+ :Width => png.width,
206
+ :BitsPerComponent => png.bits,
207
+ :Length => png.img_data.size,
208
+ :Filter => :FlateDecode
209
+
210
+ )
211
+
212
+ unless png.alpha_channel
213
+ obj.data[:DecodeParms] = {:Predictor => 15,
214
+ :Colors => png.pixel_bytes,
215
+ :Columns => png.width}
216
+ end
217
+
218
+ # append the actual image data to the object as a stream
219
+ obj << png.img_data
220
+
221
+ # sort out the colours of the image
222
+ if png.palette.empty?
223
+ obj.data[:ColorSpace] = color
224
+ else
225
+ # embed the colour palette in the PDF as a object stream
226
+ palette_obj = ref(:Length => png.palette.size)
227
+ palette_obj << png.palette
228
+
229
+ # build the color space array for the image
230
+ obj.data[:ColorSpace] = [:Indexed,
231
+ :DeviceRGB,
232
+ (png.palette.size / 3) -1,
233
+ palette_obj]
234
+ end
235
+
236
+ # *************************************
237
+ # add transparency data if necessary
238
+ # *************************************
239
+
240
+ # For PNG color types 0, 2 and 3, the transparency data is stored in
241
+ # a dedicated PNG chunk, and is exposed via the transparency attribute
242
+ # of the PNG class.
243
+ if png.transparency[:grayscale]
244
+ # Use Color Key Masking (spec section 4.8.5)
245
+ # - An array with N elements, where N is two times the number of color
246
+ # components.
247
+ val = png.transparency[:grayscale]
248
+ obj.data[:Mask] = [val, val]
249
+ elsif png.transparency[:rgb]
250
+ # Use Color Key Masking (spec section 4.8.5)
251
+ # - An array with N elements, where N is two times the number of color
252
+ # components.
253
+ rgb = png.transparency[:rgb]
254
+ obj.data[:Mask] = rgb.collect { |val| [val,val] }.flatten
255
+ elsif png.transparency[:indexed]
256
+ # TODO: broken. I was attempting to us Color Key Masking, but I think
257
+ # we need to construct an SMask i think. Maybe do it inside
258
+ # the PNG class, and store it in alpha_channel
259
+ #obj.data[:Mask] = png.transparency[:indexed]
260
+ end
261
+
262
+ # For PNG color types 4 and 6, the transparency data is stored as a alpha
263
+ # channel mixed in with the main image data. The PNG class seperates
264
+ # it out for us and makes it available via the alpha_channel attribute
265
+ if png.alpha_channel
266
+ smask_obj = ref(:Type => :XObject,
267
+ :Subtype => :Image,
268
+ :Height => png.height,
269
+ :Width => png.width,
270
+ :BitsPerComponent => 8,
271
+ :Length => png.alpha_channel.size,
272
+ :Filter => :FlateDecode,
273
+ :ColorSpace => :DeviceGray,
274
+ :Decode => [0, 1]
275
+ )
276
+ smask_obj << png.alpha_channel
277
+ obj.data[:SMask] = smask_obj
278
+ end
279
+
280
+ return obj
281
+ end
282
+
283
+ def calc_image_dimensions(info, options)
284
+ w = options[:width] || info.width
285
+ h = options[:height] || info.height
286
+
287
+ if options[:width] && !options[:height]
288
+ wp = w / info.width.to_f
289
+ w = info.width * wp
290
+ h = info.height * wp
291
+ elsif options[:height] && !options[:width]
292
+ hp = h / info.height.to_f
293
+ w = info.width * hp
294
+ h = info.height * hp
295
+ elsif options[:scale]
296
+ w = info.width * options[:scale]
297
+ h = info.height * options[:scale]
298
+ elsif options[:fit]
299
+ bw, bh = options[:fit]
300
+ bp = bw / bh.to_f
301
+ ip = info.width / info.height.to_f
302
+ if ip > bp
303
+ w = bw
304
+ h = bw / ip
305
+ else
306
+ h = bh
307
+ w = bh * ip
308
+ end
309
+ end
310
+ info.scaled_width = w
311
+ info.scaled_height = h
312
+ [w,h]
313
+ end
314
+
315
+ def detect_image_format(content)
316
+ top = content[0,128]
317
+
318
+ if top[0, 3] == "\xff\xd8\xff"
319
+ return :jpg
320
+ elsif top[0, 8] == "\x89PNG\x0d\x0a\x1a\x0a"
321
+ return :png
322
+ else
323
+ raise ArgumentError, "Unsupported Image Type"
324
+ end
325
+ end
326
+
327
+ def image_registry
328
+ @image_registry ||= {}
329
+ end
330
+
331
+ def next_image_id
332
+ @image_counter ||= 0
333
+ @image_counter += 1
334
+ end
335
+ end
336
+ end