fullcirclegroup-prawn 0.2.99.3

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 (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